├── Arduino ├── RainCounter │ └── RainCounter.ino ├── Solinst-Array │ ├── Solinst-Array.ino │ ├── Solinst-Array.ino.eightanaloginputs.hex │ └── Solinst-Array.ino.with_bootloader.eightanaloginputs.hex ├── Solinst-TestData │ └── Solinst-TestData.ino └── libraries │ ├── Arduino-SDI-12 │ ├── LICENSE │ ├── LICENSE-examples.md │ ├── README.md │ ├── SDI12.cpp │ ├── SDI12.h │ ├── examples │ │ ├── a_wild_card │ │ │ └── a_wild_card.ino │ │ ├── b_address_change │ │ │ └── b_address_change.ino │ │ ├── c_check_all_addresses │ │ │ └── c_check_all_addresses.ino │ │ ├── d_simple_logger │ │ │ └── d_simple_logger.ino │ │ ├── e_simple_parsing │ │ │ └── e_simple_parsing.ino │ │ ├── e_terminal_window │ │ │ └── e_terminal_window.ino │ │ └── f_basic_data_request │ │ │ └── f_basic_data_request.ino │ └── keywords.txt │ ├── DHT_sensor_library │ ├── DHT.cpp │ ├── DHT.h │ ├── DHT_U.cpp │ ├── DHT_U.h │ ├── README.md │ ├── examples │ │ ├── DHT_Unified_Sensor │ │ │ └── DHT_Unified_Sensor.ino │ │ └── DHTtester │ │ │ └── DHTtester.ino │ ├── keywords.txt │ └── library.properties │ └── SHT1x │ ├── CHANGES.txt │ ├── DISTRIBUTION │ ├── README.markdown │ ├── SHT1x.cpp │ ├── SHT1x.h │ ├── examples │ └── ReadSHT1xValues │ │ └── ReadSHT1xValues.ino │ └── keywords.txt ├── Design ├── PowerConvert.fzz ├── PowerConvert_schem.png ├── Solinst-20170409.fzz ├── Solinst.fzz ├── Solinst_bb.png ├── Solinst_bb2.png ├── Solinst_label.png ├── Solinst_label.psd ├── Solinst_label2.png ├── Solinst_label2.psd └── Solinst_label3.png ├── README.md ├── Solinst-Array ├── .gitignore ├── .project ├── .pydevproject ├── APIProject-1d4ee6021f22.json ├── README.md ├── modem-comm.sh ├── modem-init ├── serial_read.py ├── solinst-cron ├── solinst.ini ├── storage │ ├── .gitignore │ ├── __init__.py │ └── database.py └── web_submit.py └── pi-comm ├── README.md ├── fona └── gprs /Arduino/RainCounter/RainCounter.ino: -------------------------------------------------------------------------------- 1 | const byte interruptPin = 3; 2 | const int interval = 500; 3 | volatile unsigned long tiptime = millis(); 4 | 5 | void setup() { 6 | Serial.begin(9600); 7 | 8 | // Set up our digital pin as an interrupt 9 | pinMode(interruptPin, INPUT_PULLUP); 10 | attachInterrupt(digitalPinToInterrupt(interruptPin), count, FALLING); 11 | } 12 | 13 | void loop() { 14 | } 15 | 16 | void count() { 17 | // Grab the current ms count for common calculations 18 | unsigned long curtime = millis(); 19 | 20 | // Make sure we don't record bounces 21 | if ((curtime - tiptime) < interval) { 22 | return; 23 | } 24 | 25 | // How long since the last tip? 26 | unsigned long tipcount = curtime - tiptime; 27 | tiptime = curtime; 28 | 29 | // Calculate mm/hr from period between cup tips 30 | double rainrate = 914400.0 / tipcount; 31 | 32 | Serial.print("Cup tip: "); 33 | Serial.print(tipcount); 34 | Serial.println("ms"); 35 | 36 | Serial.print("Rain rate: "); 37 | Serial.print(rainrate); 38 | Serial.println("mm/hr"); 39 | } 40 | -------------------------------------------------------------------------------- /Arduino/Solinst-Array/Solinst-Array.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define RAINPIN 3 // Interrupt pin for Rain Gauge 6 | #define DHTPIN 4 // Data pin for the DHT 7 | #define SHTDATA 6 // Soil sensor data pin (blue) 8 | #define SHTCLK 5 // Soil sensor clock pin (yellow) 9 | #define SDIPIN 8 // Data pin for the Solinst 10 | 11 | #define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 12 | 13 | DHT dht(DHTPIN, DHTTYPE); 14 | SHT1x sht1x(SHTDATA, SHTCLK); 15 | SDI12 mySDI12(SDIPIN); 16 | 17 | volatile unsigned long tiptime = millis(); 18 | volatile double rainrate = 0.0; 19 | 20 | void setup(){ 21 | Serial.begin(9600); 22 | 23 | pinMode(RAINPIN, INPUT_PULLUP); 24 | attachInterrupt(digitalPinToInterrupt(RAINPIN), raincount, FALLING); 25 | 26 | dht.begin(); 27 | mySDI12.begin(); 28 | } 29 | 30 | void loop() { 31 | if (Serial.available() > 0) { 32 | int inByte = Serial.read(); 33 | String output = getData(); 34 | Serial.println(output); 35 | } 36 | } 37 | 38 | String getSDI(String sdiCommand) { 39 | String sdiReturn = ""; 40 | 41 | mySDI12.sendCommand(sdiCommand); 42 | delay(30); 43 | 44 | while(mySDI12.available()){ // build a string of the response 45 | char c = mySDI12.read(); 46 | if((c!='\n') && (c!='\r')) { 47 | // Serial.print(c); 48 | sdiReturn += c; 49 | delay(5); 50 | } 51 | } 52 | // Serial.println("."); 53 | 54 | // Serial.println(sdiReturn); 55 | mySDI12.flush(); //clear the line 56 | 57 | return(sdiReturn); 58 | } 59 | 60 | String getSolinst() { 61 | String sdiResponse; 62 | getSDI("0M!"); 63 | delay(5000); 64 | sdiResponse = getSDI("0D0!"); 65 | 66 | return(sdiResponse); 67 | } 68 | 69 | String getData() { 70 | String solResp = getSolinst(); 71 | int tempPos = solResp.indexOf('+'); 72 | int depthPos = solResp.indexOf('+', tempPos + 1); 73 | String solTemp = String(solResp.substring(tempPos + 1,depthPos).toFloat()); 74 | String solDepth = String(solResp.substring(depthPos + 1).toFloat()); 75 | 76 | String dhtHumid = String(dht.readHumidity()); 77 | String dhtTemp = String(dht.readTemperature()); 78 | 79 | String soilTemp = String(sht1x.readTemperatureC()); 80 | String soilHumid = String(sht1x.readHumidity()); 81 | 82 | String rainAmt = String((millis() - tiptime) > 1828800 ? 0.0 : rainrate); 83 | 84 | String output = dhtTemp + "," + dhtHumid + "," + soilTemp + "," + soilHumid + "," + solTemp + "," + solDepth + "," + rainAmt; 85 | return(output); 86 | } 87 | 88 | void raincount() { 89 | unsigned long tipcount = millis() - tiptime; 90 | tiptime = millis(); 91 | rainrate = 914400.0 / tipcount; 92 | 93 | 94 | delay(500); 95 | } 96 | -------------------------------------------------------------------------------- /Arduino/Solinst-Array/Solinst-Array.ino.eightanaloginputs.hex: -------------------------------------------------------------------------------- 1 | :100000000C94FE000C9426010C9426010C947A06A4 2 | :100010000C9456060C9432060C9426010C9426017E 3 | :100020000C9426010C9426010C9426010C942601B4 4 | :100030000C9426010C9426010C9426010C942601A4 5 | :100040000C94E8050C9426010C9438040C941204CA 6 | :100050000C9426010C9426010C9426010C94260184 7 | :100060000C9426010C9426010000000024002700B7 8 | :100070002A0000000000250028002B0000000008D6 9 | :10008000000201000003040700000000000000005F 10 | :1000900000000000230026002900040404040404D6 11 | :1000A0000404020202020202030303030303010227 12 | :1000B00004081020408001020408102001020408F6 13 | :1000C00010204E414E494E495459494E46CDCCCC54 14 | :1000D0003D0AD7233C17B7D13877CC2B329595E61C 15 | :1000E000241FB14F0A000020410000C84200401CFC 16 | :1000F0004620BCBE4CCA1B0E5AAEC59D7400407A49 17 | :1001000010F35A00A0724E18090010A5D4E80000A0 18 | :10011000E87648170000E40B54020000CA9A3B003E 19 | :100120000000E1F505000080969800000040420FB5 20 | :10013000000000A08601000000102700000000E879 21 | :1001400003000000006400000000000A000000003E 22 | :10015000000100000000002C76D888DC674F0823DF 23 | :10016000DFC1DFAE59E1B1B796E5E3E453C63AE645 24 | :1001700051997696E8E6C28426EB898C9B62ED4025 25 | :100180007C6FFCEFBC9C9F40F2BAA56FA5F4900574 26 | :100190005A2AF75C936B6CF9676DC11BFCE0E40DA8 27 | :1001A00047FEF520E6B500D0ED902E03009435779C 28 | :1001B000050080841E080000204E0A000000C80CC4 29 | :1001C000333333330F986E12831141EF8D2114892D 30 | :1001D0003BE65516CFFEE6DB18D1844B381BF77C87 31 | :1001E0001D901DA4BBE424203284725E228100C9CC 32 | :1001F000F124ECA1E53D2700F30DE80D11241FBE0D 33 | :10020000CFEFD8E0DEBFCDBF11E0A0E0B1E0E8EA7B 34 | :10021000FDE202C005900D92A433B107D9F722E0A8 35 | :10022000A4E3B1E001C01D92AD34B207E1F710E0E4 36 | :10023000CDEFD0E004C02197FE010E94870ECC3F95 37 | :10024000D107C9F70E94D40A0C94C7160C94000079 38 | :100250000895CF92DF92EF92FF920F931F93CF9367 39 | :10026000DF936C017A018B01C0E0D0E0CE15DF0591 40 | :1002700089F0D8016D918D01D601ED91FC9101902D 41 | :10028000F081E02DC6010995892B11F47E0102C091 42 | :100290002196ECCFC701DF91CF911F910F91FF9075 43 | :1002A000EF90DF90CF900895FC01918D828D98178B 44 | :1002B00061F0828DDF01A80FB11D5D968C91928D4A 45 | :1002C0009F5F9F73928F90E008958FEF9FEF089547 46 | :1002D000FC01918D828D981731F0828DE80FF11D10 47 | :1002E000858D90E008958FEF9FEF0895FC01918D2B 48 | :1002F000228D892F90E0805C9F4F821B91098F7324 49 | :100300009927089581E891E00E94760121E0892BE8 50 | :1003100009F420E0822F0895FC01848DDF01A80FED 51 | :10032000B11DA35ABF4F2C91848D90E001968F731D 52 | :100330009927848FA689B7892C93A089B1898C913C 53 | :1003400080648C93938D848D981306C00288F38902 54 | :10035000E02D80818F7D80830895EF92FF920F932F 55 | :100360001F93CF93DF93EC0181E0888F9B8D8C8D61 56 | :10037000981305C0E889F989808185FD24C0F62E8F 57 | :100380000B8D10E00F5F1F4F0F731127E02E8C8D28 58 | :10039000E8120CC00FB607FCFACFE889F989808112 59 | :1003A00085FFF5CFCE010E948C01F1CF8B8DFE0130 60 | :1003B000E80FF11DE35AFF4FF0820B8FEA89FB89AA 61 | :1003C0008081806207C0EE89FF896083E889F989AE 62 | :1003D00080818064808381E090E0DF91CF911F91E4 63 | :1003E0000F91FF90EF900895CF93DF93EC01888DEC 64 | :1003F0008823C9F0EA89FB89808185FD05C0A88929 65 | :10040000B9898C9186FD0FC00FB607FCF5CF8081AE 66 | :1004100085FFF2CFA889B9898C9185FFEDCFCE01F8 67 | :100420000E948C01E7CFDF91CF91089580E090E0AA 68 | :10043000892B29F00E94820181110C9400000895FB 69 | :10044000833081F028F4813099F08230A1F0089552 70 | :100450008730A9F08830B9F08430D1F480918000E1 71 | :100460008F7D03C0809180008F77809380000895F6 72 | :1004700084B58F7702C084B58F7D84BD0895809147 73 | :10048000B0008F7703C08091B0008F7D8093B00063 74 | :1004900008953FB7F8948091770190917801A091E9 75 | :1004A0007901B0917A0126B5A89B05C02F3F19F0BC 76 | :1004B0000196A11DB11D3FBFBA2FA92F982F8827E4 77 | :1004C000820F911DA11DB11DBC01CD0142E0660F3F 78 | :1004D000771F881F991F4A95D1F7089510921F0220 79 | :1004E0002091740180917501281769F030E0F901BD 80 | :1004F000EC5CFE4F80812F5F3F4F2F73332720939B 81 | :10050000740190E008958FEF9FEF089510927501A8 82 | :100510001092740110921F020895E091740180916D 83 | :100520007501E81741F0F0E0EC5CFE4F8081082E89 84 | :10053000000C990B08958FEF9FEF089580911F0293 85 | :1005400081110EC08091750190E0805C9F4F2091D9 86 | :100550007401821B910960E470E00E945F0E0895AF 87 | :100560008FEF9FEF08950895FC01808191810C9495 88 | :10057000C50F0E9427110F931F93CF93DF93EC01B8 89 | :1005800088819981009729F02A813B8126173707B6 90 | :1005900088F48B016F5F7F4F0E945D10009761F0C0 91 | :1005A000998388831B830A832C813D81232B11F43B 92 | :1005B000FC01108281E001C080E0DF91CF911F91AA 93 | :1005C0000F910895EF92FF920F931F93CF93DF93B4 94 | :1005D000FC01248135816115710511F480E019C099 95 | :1005E00041155105A9F07B01EC018A01020F131F8F 96 | :1005F000B8010E94BB02882389F3288139818C814C 97 | :100600009D81B701820F931F0E9440111D830C83AF 98 | :1006100081E0DF91CF911F910F91FF90EF900895AE 99 | :10062000CF93DF93EC0188819981009711F00E94AC 100 | :10063000C50F198218821D821C821B821A82DF91CB 101 | :10064000CF910895CF93DF93EC01FB014481558155 102 | :10065000608171810E94E202811103C0CE010E947B 103 | :100660001003CE01DF91CF910895EF92FF920F9387 104 | :100670001F93CF93DF93EC017B018A01BA010E94A3 105 | :10068000BB02811104C0CE010E94100307C01D836C 106 | :100690000C83B701888199810E944011CE01DF91BE 107 | :1006A000CF911F910F91FF90EF900895CF93DF931B 108 | :1006B000EC016115710559F0FB0101900020E9F78B 109 | :1006C0003197AF01461B570B0E94350302C00E94B1 110 | :1006D0001003CE01DF91CF910895EF92FF920F9317 111 | :1006E0001F93CF93DF93CDB7DEB7A1970FB6F894E2 112 | :1006F000DEBF0FBECDBF7C01CB01BA01F701118275 113 | :100700001082138212821582148242E0420F8E01FF 114 | :100710000F5F1F4F0E944711BC01C7010E94560383 115 | :10072000A1960FB6F894DEBF0FBECDBFDF91CF917B 116 | :100730001F910F91FF90EF900895FB01DC0111963E 117 | :100740001C921E9213961C921E92129715961C9242 118 | :100750001E9214978617970749F060817181611581 119 | :10076000710521F0448155810C9435030895FC01F5 120 | :100770001182108213821282158214826115710512 121 | :1007800051F0FB0101900020E9F73197AF01461BC2 122 | :10079000570B0C9435030895BF92CF92DF92EF92DE 123 | :1007A000FF920F931F93CF93DF937C016B018A011C 124 | :1007B000E9012417350720F4812F8901C42FD82F90 125 | :1007C00061E371E0C7010E94B703D60114968D91D1 126 | :1007D0009C91159708171907D0F48C179D0708F4FA 127 | :1007E000EC01D601ED91FC911197EC0FFD1FB0804B 128 | :1007F00010824D915C91BA01600F711FC7010E9478 129 | :100800005603D601ED91FC91EC0FFD1FB082C7019C 130 | :10081000DF91CF911F910F91FF90EF90DF90CF90DC 131 | :10082000BF9008951F920F920FB60F9211242F932D 132 | :100830003F934F935F936F937F938F939F93AF9368 133 | :10084000BF93EF93FF9381E891E00E948C01FF91A9 134 | :10085000EF91BF91AF919F918F917F916F915F9138 135 | :100860004F913F912F910F900FBE0F901F901895B1 136 | :100870001F920F920FB60F9211242F938F939F9375 137 | :10088000EF93FF93E0919101F09192018081E091CB 138 | :100890009701F091980182FD12C0908180919A0198 139 | :1008A0008F5F8F7320919B01821751F0E0919A0125 140 | :1008B000F0E0EF57FE4F958F80939A0101C0808141 141 | :1008C000FF91EF919F918F912F910F900FBE0F90FD 142 | :1008D0001F901895CF93DF93282F30E0F901E4584B 143 | :1008E000FF4F8491F901E255FF4FD491F901E6568B 144 | :1008F000FF4FC491CC2391F081110E942002EC2F74 145 | :10090000F0E0EE0FFF1FE057FF4FA591B491EC917F 146 | :10091000ED2381E090E021F480E002C080E090E0EF 147 | :10092000DF91CF910895EF92FF920F931F93CF9392 148 | :10093000DF9380917B0190917C01892B09F445C064 149 | :1009400080911E020E946A04892B09F43EC087E749 150 | :1009500096E00197F1F708E010E0D1E0C0E083EF06 151 | :10096000E82E8CE0F82E0150110981F0C7010197A3 152 | :10097000F1F780911E020E946A04892B11F4CD2B9D 153 | :1009800003C08D2F8095C823DD0FEDCF83EF9CE052 154 | :10099000FC013197F1F70197F1F78091750190E033 155 | :1009A0009C012F5F3F4F2F7333274091740150E01C 156 | :1009B0002417350721F481E080931F0206C0FC0153 157 | :1009C000EC5CFE4FC08320937501DF91CF911F91A6 158 | :1009D0000F91FF90EF9008951F93CF93DF93282FEF 159 | :1009E00030E0F901E458FF4F8491F901E255FF4FDF 160 | :1009F000D491F901E656FF4FC491CC23C9F0162FCC 161 | :100A000081110E942002EC2FF0E0EE0FFF1FEE5844 162 | :100A1000FF4FA591B4918FB7F894111105C09C9127 163 | :100A2000ED2FE095E92302C0EC91ED2BEC938FBF05 164 | :100A3000DF91CF911F910895CF93DF9390E0FC0158 165 | :100A4000E255FF4F2491FC01E656FF4F8491882325 166 | :100A500061F190E0880F991FFC01E859FF4FC591A3 167 | :100A6000D491FC01EE58FF4FA591B491611109C0DA 168 | :100A70009FB7F8948881209582238883EC912E2358 169 | :100A80000BC0623061F49FB7F8943881822F809553 170 | :100A900083238883EC912E2B2C939FBF06C08FB7A6 171 | :100AA000F894E8812E2B28838FBFDF91CF91089592 172 | :100AB0008F929F92AF92BF92CF92DF92EF92FF926E 173 | :100AC0006B017C010E9449024B015C01C114D104FD 174 | :100AD000E104F104F1F00E944902DC01CB01881924 175 | :100AE0009909AA09BB09883E9340A105B10570F395 176 | :100AF00021E0C21AD108E108F10888EE880E83E0EF 177 | :100B0000981EA11CB11CC114D104E104F10419F711 178 | :100B1000DDCFFF90EF90DF90CF90BF90AF909F9090 179 | :100B20008F900895EF92FF920F931F93CF93DF93CF 180 | :100B300000D000D000D0CDB7DEB78C017B0161E3DF 181 | :100B400071E00E94B703B701CE0101960E949D0398 182 | :100B5000CE0101960E943108CE0101960E94B40296 183 | :100B60006EE170E080E090E00E94580580E292E043 184 | :100B70000E949E02892BB9F080E292E00E946E02F0 185 | :100B80008A30A1F38D3091F389831A8241E050E0DD 186 | :100B9000BE016F5F7F4FC8010E94E20265E070E016 187 | :100BA00080E090E0E1CF80E292E00E948602C801FE 188 | :100BB0000E941808C80126960FB6F894DEBF0FBE33 189 | :100BC000CDBFDF91CF911F910F91FF90EF900895CE 190 | :100BD0001F920F920FB60F9211242F933F938F9372 191 | :100BE0009F93AF93BF9380917D0190917E01A091DF 192 | :100BF0007F01B09180013091760123E0230F2D37E2 193 | :100C000020F40196A11DB11D05C026E8230F029610 194 | :100C1000A11DB11D2093760180937D0190937E01EB 195 | :100C2000A0937F01B093800180917701909178012A 196 | :100C3000A0917901B0917A010196A11DB11D809317 197 | :100C4000770190937801A0937901B0937A01BF91D5 198 | :100C5000AF919F918F913F912F910F900FBE0F9069 199 | :100C60001F9018951F920F920FB60F9211242F9379 200 | :100C70003F934F935F936F937F938F939F93AF9324 201 | :100C8000BF93EF93FF930E949304FF91EF91BF9165 202 | :100C9000AF919F918F917F916F915F914F913F9114 203 | :100CA0002F910F900FBE0F901F9018951F920F92CB 204 | :100CB0000FB60F9211242F933F934F935F936F932F 205 | :100CC0007F938F939F93AF93BF93EF93FF930E9474 206 | :100CD0009304FF91EF91BF91AF919F918F917F917D 207 | :100CE0006F915F914F913F912F910F900FBE0F9099 208 | :100CF0001F9018951F920F920FB60F9211242F93E9 209 | :100D00003F934F935F936F937F938F939F93AF9393 210 | :100D1000BF93EF93FF930E949304FF91EF91BF91D4 211 | :100D2000AF919F918F917F916F915F914F913F9183 212 | :100D30002F910F900FBE0F901F9018956230C9F53C 213 | :100D400061E080911E020E941C0560E080911E02FD 214 | :100D50000E94EC0420911E02283038F02E3040F022 215 | :100D6000263148F4ECE6F0E008C0EDE6F0E005C01E 216 | :100D7000EBE6F0E002C0E0E0F0E03081283038F44B 217 | :100D800081E090E001C0880F2A95EAF70FC0422F5A 218 | :100D900050E02E3018F44850510902C04E5051090D 219 | :100DA00081E090E001C0880F4A95EAF7809583239F 220 | :100DB000C3C0633039F461E080911E020E941C05BB 221 | :100DC000F8940895643009F050C060E080911E02EC 222 | :100DD0000E94EC0460E080911E020E941C05789441 223 | :100DE00080911E02863118F0E0E0F0E002C0E8E6F3 224 | :100DF000F0E09081883050F021E08E3008F420E05F 225 | :100E000081E001C0880F2A95EAF701C084E0892BB0 226 | :100E1000808390911E02983038F09E3040F09631D9 227 | :100E200048F0E0E0F0E008C0EDE6F0E005C0EBE6F9 228 | :100E3000F0E002C0ECE6F0E04081983030F481E070 229 | :100E400001C0880F9A95EAF70EC0292F30E09E3036 230 | :100E500018F42850310902C02E50310981E001C038 231 | :100E6000880F2A95EAF7842B67C060E080911E0204 232 | :100E70000E94EC0460E080911E020E941C052091FB 233 | :100E80001E02283038F02E3040F0263148F0E0E0E5 234 | :100E9000F0E008C0EDE6F0E005C0EBE6F0E002C0EF 235 | :100EA000ECE6F0E03081283038F481E090E001C0D9 236 | :100EB000880F2A95EAF70FC0422F50E02E3018F421 237 | :100EC0004850510902C04E50510981E090E001C0E4 238 | :100ED000880F4A95EAF780958323808390911E02BC 239 | :100EE000983038F09E3040F0963148F0E0E0F0E085 240 | :100EF00008C0EDE6F0E005C0EBE6F0E002C0ECE68D 241 | :100F0000F0E08081811119C0963118F0E0E0F0E046 242 | :100F100002C0E8E6F0E02081983060F031E09E30D9 243 | :100F200008F430E081E090E001C0880F3A95EAF7DC 244 | :100F3000809501C08BEF8223808308958F929F92CA 245 | :100F4000AF92BF92CF92DF92EF92FF92CF93DF9357 246 | :100F5000A0913B02882311F03A2F01C030E080912C 247 | :100F60003C0290E0880F991F80579F4FC09041022C 248 | :100F7000D0904202E0904302F090440240E050E002 249 | :100F8000BA01FC01C591D49128812A2323130FC0F3 250 | :100F90004A015B012FEF821A920AA20AB20A4C158B 251 | :100FA0005D056E057F0538F4B501A401EACF342F45 252 | :100FB000252FCB0104C030E020E080E090E0632FDB 253 | :100FC000722FDF91CF91FF90EF90DF90CF90BF9085 254 | :100FD000AF909F908F900895EF92FF920F931F9381 255 | :100FE000CF93DF93E82EF62E08E010E0C0E0D0E0CB 256 | :100FF00061E08F2D0E94EC046AE070E080E090E0F8 257 | :101000000E945805CC0FDD1F8E2D0E946A04C80F68 258 | :10101000D91F60E08F2D0E94EC040150110941F7A7 259 | :10102000CE01DF91CF911F910F91FF90EF90089526 260 | :10103000CF93DF93FC01448155816081718181E808 261 | :1010400091E00E942901EC0142E050E06FE271E082 262 | :1010500081E891E00E9429018C0F9D1FDF91CF91C3 263 | :1010600008955F926F927F928F929F92AF92BF92FC 264 | :10107000CF92DF92EF92FF920F931F93CF93DF9364 265 | :101080007C0163E080E292E00E949E06C0911E0215 266 | :1010900061E08C2F0E94EC048BE09DEB0197F1F74F 267 | :1010A00060E08C2F0E94EC048BE393E80197F1F74A 268 | :1010B00000E010E033EFA32E3CE0B32E43EF842E8C 269 | :1010C0004CE0942EF701848195810817190708F0E8 270 | :1010D00048C0D701ED91FC91309729F41092460257 271 | :1010E000E6E4F2E002C0E00FF11F8081982F092EA4 272 | :1010F00092959025092E9695969590259F5F91FB48 273 | :10110000CC24C0F8D12C96013695322F2227379562 274 | :101110002795582E522A61E08C2F0E94EC04C501BD 275 | :101120000197F1F728E0622E712CD1E08D2F8521F7 276 | :1011300011F060E001C061E08C2F0E94EC04C50159 277 | :101140000197F1F7DD0FB1E06B1A710879F760E0F4 278 | :101150008C2F0E94EC04C4010197F1F70F5F1F4F21 279 | :10116000B1CF64E080E292E0DF91CF911F910F91C7 280 | :10117000FF90EF90DF90CF90BF90AF909F908F90B7 281 | :101180007F906F905F900C949E06CF93DF93EC015D 282 | :1011900041E050E062E371E00E94E202811103C08D 283 | :1011A000CE010E941003CE01DF91CF910895CF931D 284 | :1011B000DF93D82FC62F61E00E941C0561E08C2FC1 285 | :1011C0000E941C0561E08D2F0E94EC0461E08C2FD1 286 | :1011D0000E94EC0460E08C2FDF91CF910C94EC0422 287 | :1011E000EF92FF920F931F93CF93DF93C82FF92EA7 288 | :1011F000D62FE72E60E00E941C0561E08D2F0E9433 289 | :101200001C056D2F7E2D8C2F9F2D0E94EC0700E07A 290 | :1012100010E0182F61E08C2F0E941C0561E08C2FDC 291 | :101220000E94EC0460E08C2F0E94EC0461E08D2FA2 292 | :101230000E94EC0460E08D2F0E94EC0460E08C2F93 293 | :101240000E941C056D2F7E2D8C2F9F2D0E94EC0778 294 | :10125000802B912BDF91CF911F910F91FF90EF90F9 295 | :1012600008951F93CF93DF93182F60E00E941C0511 296 | :10127000C4E6D0E06AE070E080E090E00E945805AB 297 | :10128000812F0E946A04892B11F0219799F7DF9131 298 | :10129000CF911F910895EF92FF920F931F93CF93D9 299 | :1012A000DF937C01D62FC42F61E08D2F0E941C0597 300 | :1012B00061E08C2F0E941C0561E08D2F0E94EC04E0 301 | :1012C00061E08C2F0E94EC0460E08D2F0E94EC0402 302 | :1012D00060E08C2F0E94EC0461E08C2F0E94EC04F3 303 | :1012E00061E08D2F0E94EC0460E08C2F0E94EC04E2 304 | :1012F00007E010E0FF24B701002E02C07595679546 305 | :101300000A94E2F7617077278D2F0E94EC0461E068 306 | :101310008C2F0E94EC0460E08C2F0E94EC040150A2 307 | :10132000110948F761E08C2F0E94EC0460E08D2FDA 308 | :101330000E941C058D2F0E946A0460E08C2F0E9481 309 | :10134000EC048D2FDF91CF911F910F91FF90EF90C3 310 | :101350000C946A040F931F93CF93DF93CEE2D2E0F5 311 | :101360004A815B816881798183E090E00E944B092A 312 | :10137000888199810E9431096A817B818881998164 313 | :101380000E94F0088C016A817B81888199810E948A 314 | :10139000D708B801110F880B990B0E945615DF91E1 315 | :1013A000CF911F910F910895CF92DF92EF92FF920C 316 | :1013B0000F931F93CF93DF93CDB7DEB7C054D140C7 317 | :1013C0000FB6F894DEBF0FBECDBF2FB7F894809153 318 | :1013D0007D0190917E01A0917F01B09180012FBF8E 319 | :1013E00040913D0250913E0260913F027091400257 320 | :1013F0008C019D01041B150B260B370BB901A801AD 321 | :10140000403D57406105710518F480914502BCC00C 322 | :1014100080933D0290933E02A0933F02B09340021E 323 | :101420001092380210923702109236021092350252 324 | :101430001092340261E0809139020E94EC046AEF5C 325 | :1014400070E080E090E00E94580561E080913902F0 326 | :101450000E941C0560E0809139020E94EC0464E166 327 | :1014600070E080E090E00E945805F89461E080917F 328 | :1014700039020E94EC048BE990E00197F1F762E0F9 329 | :10148000809139020E941C0583E290E00197F1F7F8 330 | :1014900080E00E949E07672B682B692B21F4109235 331 | :1014A000450278943EC081E00E949E07672B682B1E 332 | :1014B000692BA9F38E010F5F1F4F6E012FEBC21A2C 333 | :1014C0002EEFD20A780180E00E949E07F701608328 334 | :1014D00071838283938381E00E949E07F701648376 335 | :1014E000758386839783F8E0EF0EF11CEC14FD04FE 336 | :1014F00051F7789420E030E0F80140815181628119 337 | :101500007381C480D580E680F7804115510561055F 338 | :10151000710529F0C114D104E104F10421F4109201 339 | :10152000450280E031C0F90183E0F595E7958A95A1 340 | :10153000E1F7EC5CFD4F8081880F4C155D056E0571 341 | :101540007F0508F4816080832F5F3F4F085F1F4F46 342 | :101550002832310589F62091380230E0409134027A 343 | :101560008091350290E0840F911D40913602840FE6 344 | :10157000911D40913702840F911D99272817390733 345 | :1015800071F681E080934502C05CDE4F0FB6F8949F 346 | :10159000DEBF0FBECDBFDF91CF911F910F91FF90A6 347 | :1015A000EF90DF90CF900895CF93DF93CDB7DEB764 348 | :1015B000E6970FB6F894DEBF0FBECDBF789484B522 349 | :1015C000826084BD84B5816084BD85B5826085BD3F 350 | :1015D00085B5816085BD80916E00816080936E00CD 351 | :1015E00010928100809181008260809381008091BF 352 | :1015F0008100816080938100809180008160809370 353 | :1016000080008091B10084608093B1008091B0002F 354 | :1016100081608093B00080917A00846080937A002A 355 | :1016200080917A00826080937A0080917A00816054 356 | :1016300080937A0080917A00806880937A0010927B 357 | :10164000C100E0919101F091920182E08083E091EC 358 | :101650008D01F0918E011082E0918F01F091900147 359 | :101660008FEC808310929901E0919501F0919601A1 360 | :1016700086E08083E0919301F09194018081806104 361 | :101680008083E0919301F091940180818860808350 362 | :10169000E0919301F0919401808180688083E091D2 363 | :1016A0009301F091940180818F7D808362E080912D 364 | :1016B00039020E941C0580E398EFAFEFBFEF8093E3 365 | :1016C0003D0290933E02A0933F02B093400262E03D 366 | :1016D00080E292E00E949E0680917B0190917C01C5 367 | :1016E0008052924059F062E080E292E00E949E06B1 368 | :1016F00080E292E090937C0180937B0181E891E00D 369 | :101700000E947601181619060CF05FC281E891E07C 370 | :101710000E94540161E371E0CE018B960E94B703F1 371 | :1017200066E271E0CE0107960E94B703BE01695FD1 372 | :101730007F4FCE0101960E949205CE0101960E9434 373 | :10174000B402CE0107960E94B40268E873E180E01B 374 | :1017500090E00E9458056AE271E0CE0107960E946F 375 | :10176000B703BE01695F7F4FCE0101960E949205CB 376 | :101770008BA59CA50097A9F069817A8161157105F7 377 | :1017800071F04DA55EA52D813E814217530738F0BB 378 | :101790000E9440118D819E8198AB8FA712C00E943C 379 | :1017A000C50F89819A819CA78BA78B819C819EA75D 380 | :1017B0008DA78D819E8198AB8FA71A8219821C827A 381 | :1017C0001B821E821D82CE0101960E94B402CE01B0 382 | :1017D00007960E94B402EFA4F8A8E114F10469F09E 383 | :1017E000CBA4DCA46BE270E0C6010E943511009727 384 | :1017F00021F08C010C191D0902C00FEF1FEF0F5FC4 385 | :101800001F4F0E151F0578F4CBA4DCA46BE270E02B 386 | :10181000C601800F911F0E943511009721F07C01B5 387 | :10182000EC18FD0803C0EE24EA94FE2C9701A801F1 388 | :10183000BE01655D7F4FCE0101960E94CC03898178 389 | :101840009A81009729F00E946711AB01BC0103C087 390 | :1018500040E050E0BA0122E0CE0185960E946D037F 391 | :10186000CE0101960E94B4022FA538A9A7014F5FAF 392 | :101870005F4FBE01655D7F4FCE0101960E94CC0394 393 | :1018800089819A81009729F00E946711AB01BC0100 394 | :1018900003C040E050E0BA0122E0CE014F960E9422 395 | :1018A0006D03CE0101960E94B4020E94D4098823E0 396 | :1018B000A1F180913A028B3041F178F1855182306B 397 | :1018C00060F56091340270E080E090E00E94541571 398 | :1018D00020E030E040E853E40E94B5156B017C0144 399 | :1018E00080913502682F70E080E090E00E945615EC 400 | :1018F0009B01AC01C701B6010E948E0E2DEC3CECA1 401 | :101900004CEC5DE30E94B5150CC06091340270E0B0 402 | :1019100080E090E00E94541504C060E070E080EC2C 403 | :101920009FE722E0AB01BC01CE0149960E946D0306 404 | :101930000E94D4098823D1F180913A028B3029F09A 405 | :10194000A8F18551823048F031C06091360270E0D4 406 | :1019500080E090E00E9454152DC010913602612F56 407 | :101960006F7770E080E090E00E94561520E030E054 408 | :1019700040E853E40E94B5156B017C018091370269 409 | :10198000682F70E080E090E00E9456159B01AC014A 410 | :10199000C701B6010E948E0E2DEC3CEC4CEC5DE3D1 411 | :1019A0000E94B51517FF06C0905804C060E070E0B3 412 | :1019B00080EC9FE722E0AB01BC01CE0143960E9480 413 | :1019C0006D030E94AA090E94FA0E072E000C880BD4 414 | :1019D000990B0E9456152AE037ED43E25CE30E9422 415 | :1019E000B51520E030E040E252E40E948D0EAB01DC 416 | :1019F000BC0122E0CE010D960E946D0340913002A1 417 | :101A00005091310260912E0270912F0285E090E09A 418 | :101A10000E944B0980912E0290912F020E94310961 419 | :101A2000609130027091310280912E0290912F02CC 420 | :101A30000E94F0088C016091300270913102809117 421 | :101A40002E0290912F020E94D708B801110F880B27 422 | :101A5000990B0E9456156B017C0124E533EE45E29B 423 | :101A60005DE30E94B51520E030E040E850E40E94BC 424 | :101A70008D0E4B015C0122EA37EE4BE356EBC701BA 425 | :101A8000B6010E94B515A70196010E94B5159B01EC 426 | :101A9000AC01C501B4010E948E0E4B015C010E9495 427 | :101AA000AA090E94FA0E072E000C880B990B0E94BF 428 | :101AB00056152AE037ED43E25CE30E94B51520E0BD 429 | :101AC00030E040E252E40E948D0E20E030E048EC2D 430 | :101AD00051E40E948D0E2B013C012CEA35EC47EAC3 431 | :101AE00058E3C701B6010E94B5152AE037ED43E27D 432 | :101AF0005CE30E948E0E9B01AC01C301B2010E9407 433 | :101B0000B515A50194010E948E0EAB01BC0122E027 434 | :101B1000CE0107960E946D03BE016D5E7F4FCE0120 435 | :101B200001960E949D03CE0101960E94C508BE0148 436 | :101B3000675E7F4F0E9422030E94C508BE01635F5B 437 | :101B40007F4F0E9422030E94C508BE01695F7F4F3C 438 | :101B50000E9422030E94C508BE016B5D7F4F0E9458 439 | :101B600022030E94C508BE01615E7F4F0E942203CE 440 | :101B7000BC01CE01C1960E949D03CE0101960E9438 441 | :101B8000B402CE0107960E94B402CE010D960E94C7 442 | :101B9000B402CE0143960E94B402CE0149960E943F 443 | :101BA000B402CE014F960E94B402CE0185960E94E7 444 | :101BB000B402CE018B960E94B402CE01C1960E945F 445 | :101BC0001808CE01C1960E94B4020E94160296CD5A 446 | :101BD0008AE191E0909321028093200260E080E20C 447 | :101BE00092E00C949E060F931F93E1E8F1E01382BC 448 | :101BF000128248EE53E060E070E0448355836683D0 449 | :101C000077838AE091E09183808385EC90E09587EB 450 | :101C1000848784EC90E09787868780EC90E0918BB6 451 | :101C2000808B81EC90E0938B828B82EC90E0958BA3 452 | :101C3000848B86EC90E0978B868B118E128E138EA0 453 | :101C4000148EA4E3B2E083E015968C93159786E199 454 | :101C500016968C931697E1EBF0E0E4911796EC93CF 455 | :101C60001797EDE9F0E0E4911896EC93189700E8E7 456 | :101C70001EE320E030E01D960D931D932D933C93C1 457 | :101C80005097EEE2F2E084E090E09183808385E07B 458 | :101C900090E093838283E0E2F2E013821282448335 459 | :101CA0005583668377838AE191E0918380831092E4 460 | :101CB0001F0286E080931E021F910F91089597FBEB 461 | :101CC000072E16F4009407D077FD09D00E94730EFA 462 | :101CD00007FC05D03EF4909581959F4F089570952F 463 | :101CE00061957F4F0895AA1BBB1B51E107C0AA1F36 464 | :101CF000BB1FA617B70710F0A61BB70B881F991FAD 465 | :101D00005A95A9F780959095BC01CD010895EE0FE5 466 | :101D1000FF1F0590F491E02D09945058BB27AA2786 467 | :101D20000E94A50E0C943C160E942E1638F00E94BC 468 | :101D3000351620F039F49F3F19F426F40C942B1635 469 | :101D40000EF4E095E7FB0C942516E92F0E944D1642 470 | :101D500058F3BA17620773078407950720F079F4E0 471 | :101D6000A6F50C946F160EF4E0950B2EBA2FA02D4D 472 | :101D70000B01B90190010C01CA01A0011124FF2738 473 | :101D8000591B99F0593F50F4503E68F11A16F04033 474 | :101D9000A22F232F342F4427585FF3CF4695379532 475 | :101DA0002795A795F0405395C9F77EF41F16BA0BF7 476 | :101DB000620B730B840BBAF09150A1F0FF0FBB1FA5 477 | :101DC000661F771F881FC2F70EC0BA0F621F731FEE 478 | :101DD000841F48F4879577956795B795F7959E3F4B 479 | :101DE00008F0B0CF9395880F08F09927EE0F9795DC 480 | :101DF000879508950E94010F6894B1110C94701694 481 | :101E000008950E94551688F09F5798F0B92F99278A 482 | :101E1000B751B0F0E1F0660F771F881F991F1AF0D5 483 | :101E2000BA95C9F714C0B13091F00E946F16B1E0B5 484 | :101E300008950C946F16672F782F8827B85F39F0B4 485 | :101E4000B93FCCF3869577956795B395D9F73EF46E 486 | :101E500090958095709561957F4F8F4F9F4F089516 487 | :101E6000CF93DF938230910510F482E090E0E0910F 488 | :101E70004902F0914A0220E030E0C0E0D0E0309723 489 | :101E800011F14081518148175907C0F0481759078F 490 | :101E900061F482819381209719F09B838A832BC000 491 | :101EA00090934A028093490226C02115310519F00A 492 | :101EB0004217530718F49A01BE01DF01EF010280B7 493 | :101EC000F381E02DDCCF2115310509F1281B390BF9 494 | :101ED0002430310590F412968D919C9113976115E1 495 | :101EE000710521F0FB019383828304C090934A0221 496 | :101EF00080934902FD01329644C0FD01E20FF31FB9 497 | :101F000081939193225031092D933C933AC02091B3 498 | :101F1000470230914802232B41F420910201309175 499 | :101F20000301309348022093470220910001309131 500 | :101F300001012115310541F42DB73EB7409104014F 501 | :101F400050910501241B350BE0914702F0914802A6 502 | :101F5000E217F307A0F42E1B3F0B2817390778F080 503 | :101F6000AC014E5F5F4F2417350748F04E0F5F1FDF 504 | :101F700050934802409347028193919302C0E0E05E 505 | :101F8000F0E0CF01DF91CF9108950F931F93CF938E 506 | :101F9000DF93009709F48CC0FC0132971382128200 507 | :101FA0000091490210914A020115110581F4208126 508 | :101FB0003181820F931F20914702309148022817E8 509 | :101FC000390779F5F0934802E093470271C0D801D0 510 | :101FD00040E050E0AE17BF0750F412962D913C91AF 511 | :101FE0001397AD012115310509F1D901F3CF9D01F9 512 | :101FF000DA013383228360817181860F971F8217F4 513 | :10200000930769F4EC0128813981260F371F2E5F71 514 | :102010003F4F318320838A819B8193838283452B29 515 | :1020200029F4F0934A02E093490242C01396FC93CC 516 | :10203000EE931297ED01499159919E01240F351F9E 517 | :10204000E217F30771F480819181840F951F029646 518 | :1020500011969C938E938281938113969C938E9379 519 | :102060001297E0E0F0E0D80112968D919C911397C1 520 | :10207000009719F0F8018C01F6CF8D919C91980191 521 | :102080002E5F3F4F820F931F2091470230914802ED 522 | :102090002817390769F4309729F410924A021092F0 523 | :1020A000490202C013821282109348020093470231 524 | :1020B000DF91CF911F910F910895A0E0B0E0E3E68A 525 | :1020C000F0E10C948516EC01009721F4CB010E94FD 526 | :1020D000300FB8C0FC01E60FF71F9C0122503109F8 527 | :1020E000E217F30708F4ACC0D9010D911C911197C8 528 | :1020F00006171707B0F00530110508F49FC0C80196 529 | :1021000004978617970708F499C002501109061B17 530 | :10211000170B019311936D937C93CF010E94C50F10 531 | :102120008DC05B01A01AB10A4C01800E911EA091D6 532 | :102130004902B0914A0240E050E0E12CF12C1097A6 533 | :1021400009F44AC0A815B905D1F56D907C90119796 534 | :10215000630182E0C80ED11CCA14DB0480F1A30124 535 | :102160004A195B096A0182E0C80ED11C1296BC9024 536 | :1021700012971396AC91B5E0CB16D10440F0B28221 537 | :10218000A38351834083D9016D937C930AC00E5F72 538 | :102190001F4FC301800F911FF90191838083EB2DA5 539 | :1021A000FA2FE114F10431F0D7011396FC93EE936A 540 | :1021B000129744C0F0934A02E09349023FC08D91C8 541 | :1021C0009C9111974817590708F4AC017D011296AC 542 | :1021D0000D90BC91A02DB3CF809147029091480201 543 | :1021E00088159905E1F446175707C8F48091000156 544 | :1021F00090910101009741F48DB79EB74091040181 545 | :1022000050910501841B950BE817F907C8F4F0936A 546 | :102210004802E0934702F901718360830FC0CB014C 547 | :102220000E94300F7C01009759F0A801BE010E9466 548 | :102230002C11CE010E94C50FC70104C0CE0102C0FF 549 | :1022400080E090E0CDB7DEB7EEE00C94A11681E01F 550 | :1022500090E0F8940C94C716FB01DC0102C00190D9 551 | :102260000D9241505040D8F70895FC018191861796 552 | :1022700021F08823D9F7992708953197CF01089540 553 | :10228000FB01DC0101900D920020E1F70895EF922F 554 | :102290000F931F93CF93DF93E80147FD02C034E013 555 | :1022A00001C034E1E42F440FFF0BF7FF03C0F195A9 556 | :1022B000E195F109E32E022F2E2FAE010E946B1142 557 | :1022C000CE01DF91CF911F910F91EF900895662776 558 | :1022D00077270C94F9124F925F926F927F929F92A0 559 | :1022E000AF92BF92CF92DF92EF92FF920F931F9324 560 | :1022F000CF93DF93CDB7DEB729970FB6F894DEBF43 561 | :102300000FBECDBF6A01122FB02E2BE3201720F095 562 | :10231000FF24F394F00E02C0BCE3FB2E0F2D27E048 563 | :10232000AE014F5F5F4F0E945614AC018981982F18 564 | :102330009970913031F0E1FC06C0E0FE06C090E2F9 565 | :1023400005C09DE203C09BE201C090E0EE2DE0716C 566 | :1023500083FF3CC0911102C083E001C084E081177B 567 | :1023600018F4212F281B01C020E0E1110BC0F60159 568 | :10237000822F30E2882319F031938150FBCFC20EB7 569 | :10238000D11C20E0992329F0D6019C93F6013196C7 570 | :102390006F01C6010396E2FE0AC03EE4D6013C93FB 571 | :1023A00041E411964C93119712963C9306C03EE679 572 | :1023B000F601308341E641833283FC01322F40E253 573 | :1023C000332309F442C041933150FACF82FF44C015 574 | :1023D000911102C083E001C084E0811718F4212F1D 575 | :1023E000281B01C020E0E1110BC0F601822F30E272 576 | :1023F000882319F031938150FBCFC20ED11C20E00D 577 | :10240000992329F0D6019C93F60131966F01C601FC 578 | :102410000396E2FE0BC039E4D6013C933EE41196EC 579 | :102420003C93119736E412963C9307C039E6F601C7 580 | :1024300030833EE6318336E63283FC01322F40E2C0 581 | :10244000332319F041933150FBCFFC01E20FF11D12 582 | :1024500010828EEF9FEFB7C0F1E0911101C0F0E064 583 | :102460006F2F70E01416150624F49A012F5F3F4F6A 584 | :1024700002C021E030E0260F371FBB2029F06B2D72 585 | :1024800070E06F5F7F4F02C060E070E0260F371F83 586 | :10249000612F70E0261737071CF4121B212F01C093 587 | :1024A00020E03E2D387159F4D601322F60E23323FB 588 | :1024B00019F06D933150FBCFC20ED11C20E0FF23E9 589 | :1024C00031F0D6019C93B6016F5F7F4F6B01E11134 590 | :1024D0000BC0F601922F30E3992319F031939150FC 591 | :1024E000FBCFC20ED11C20E09F2D940F3A81782F94 592 | :1024F0007071A72E84FF03C0313309F4915019166F 593 | :1025000024F4993018F098E001C091E0E42F852F71 594 | :1025100057FF02C0E0E080E06E2F782FE0E0F0E0AF 595 | :10252000AEE29A2E3A01691A71082A01461A570A30 596 | :102530000B2D10E01195019511096F3F8FEF780772 597 | :1025400029F4D6019C92C60101966C0146175707E3 598 | :1025500084F0661677066CF47F01E40CF51CA1E0AC 599 | :10256000B0E0AC0FBD1FEA0EFB1ED7011196BC9068 600 | :1025700002C090E3B92E615071093196C6010196EF 601 | :102580007C016017710724F0D601BC926C01D5CF95 602 | :102590006417750741F4363320F4353321F4A11064 603 | :1025A00002C081E3B82EF601B082F701822F90E2DB 604 | :1025B000882319F091938150FBCFF701E20FF11DB1 605 | :1025C000108280E090E029960FB6F894DEBF0FBE2F 606 | :1025D000CDBFDF91CF911F910F91FF90EF90DF90D2 607 | :1025E000CF90BF90AF909F907F906F905F904F90F3 608 | :1025F0000895A0E0B0E0EFEFF2E10C948516EC0155 609 | :102600007B016115710519F0DB018D939C938E019F 610 | :102610000F5F1F4F7880872D90E00E942E15892B29 611 | :1026200011F0E801F4CFBDE27B1205C00F5F1F4F30 612 | :102630007980C1E008C0EBE27E1204C08E010E5F1B 613 | :102640001F4F7980C0E06801F1E0CF1AD10843E064 614 | :1026500050E06AEC70E0C6010E943715892BF1F456 615 | :10266000680122E0C20ED11C45E050E065EC70E04C 616 | :10267000C6010E943715892B21F4680187E0C80E36 617 | :10268000D11CE114F10419F0D701CD92DC92C111F3 618 | :10269000FFC060E070E080E89FE703C143E050E0E6 619 | :1026A00062EC70E0C6010E943715892B51F4E114E9 620 | :1026B000F10409F4F2C00E5F1F4FF701118300838C 621 | :1026C000ECC0680160E070E0CB0100E010E0F601D2 622 | :1026D000D0EDD70DDA3058F52C2F2260622E2C2F3A 623 | :1026E0002870C2FF05C0211128C00F5F1F4F25C0F1 624 | :1026F000222311F001501109A5E0B0E09B01AC01CB 625 | :102700000E9476164B015C01880C991CAA1CBB1C0C 626 | :10271000C501B4016D0F711D811D911D6839A9E9B5 627 | :102720007A078A07A9E19A0740F0C66005C0DE3F34 628 | :1027300051F4C3FD44C0C8606C2EBFEFCB1ADB0A56 629 | :102740007080C62DC4CF2D2F2F7D2531C1F540813E 630 | :102750004D3211F4C06106C04B3221F0319621E0B8 631 | :1027600030E006C03296D60111964C9122E030E05E 632 | :10277000A0EDA40FAA3018F0E21BF30B20C040E03C 633 | :1027800050E04038BCE05B075CF49A01220F331F35 634 | :10279000220F331F420F531F440F551F4A0F511D65 635 | :1027A0003196DF0111972C91A0EDA20FAA3048F3CA 636 | :1027B000C4FF03C0519541955109040F151FC1FF76 637 | :1027C00007C0E114F10421F03197D701ED93FC9398 638 | :1027D0000E945415C370C33019F06B017C0106C010 639 | :1027E0006B017C01F7FAF094F7F8F09420E030E008 640 | :1027F000A901C701B6010E944F15882309F445C0FD 641 | :1028000017FF06C0119501951109C1EED0E002C075 642 | :10281000C9EFD0E05E01B8E1AB1AB1084601BE2DA8 643 | :10282000AF2D90E2E92EF12C0E151F0584F0FE016C 644 | :102830002591359145915491B4018B2F9A2F0E9487 645 | :10284000B5154B01B82FA92F0E191F09EDCF2497ED 646 | :10285000F594E794CA15DB0539F76401EB2EFA2EDF 647 | :102860008E2D880F8F2D881F8F3F49F020E030E09C 648 | :10287000A901C701B6010E944F15811106C082E26D 649 | :1028800090E090934C0280934B02C701B60109C0BF 650 | :1028900060E070E080E89FEF04C060E070E080ECF2 651 | :1028A0009FE7CDB7DEB7EEE00C94A116283008F014 652 | :1028B00027E03327DA01990F311D87FD91600096DB 653 | :1028C0006105710539F432602E5F3D9330E32A953E 654 | :1028D000E1F708959F3F30F080387105610509F0F8 655 | :1028E0003C5F3C5F3D93913008F08068911DDF9321 656 | :1028F000CF931F930F93FF92EF92192F987F969586 657 | :10290000E92F96959695E90FFF27E95AFE4F9927EB 658 | :102910003327EE24FF24A701E701059008940794CC 659 | :1029200028F4360FE71EF81E491F511D660F771F4A 660 | :10293000881F991F0694A1F70590079428F4E70EC5 661 | :10294000F81E491F561FC11D770F881F991F661F4C 662 | :102950000694A1F70590079428F4F80E491F561F16 663 | :10296000C71FD11D880F991F661F771F0694A1F7F7 664 | :102970000590079420F4490F561FC71FD81F990FC1 665 | :10298000661F771F881F0694A9F78491109517700A 666 | :1029900041F0D695C79557954795F794E7941A95C2 667 | :1029A000C1F7EDEFF0E068941590159135916591C0 668 | :1029B000959105907FE27395E118F10A430B560B50 669 | :1029C000C90BD009C0F7E10CF11E431F561FC91FE8 670 | :1029D000D01D7EF4703311F48A95E6CFE89401504F 671 | :1029E00030F0080F0AF40027021708F4202F23956F 672 | :1029F000022F7A3328F079E37D932A95E9F710C006 673 | :102A00007D932A9589F6069497956795379517953E 674 | :102A10001794E118F10A430B560BC90BD00998F033 675 | :102A200023957E9173957A3308F070E37C9320139D 676 | :102A3000B8F77E9170617D9330F0839571E37D935B 677 | :102A400070E32A95E1F71124EF90FF900F911F9109 678 | :102A5000CF91DF91992787FD9095089591110C945E 679 | :102A60002216803219F089508550C8F70895FB016D 680 | :102A7000DC014150504088F08D9181341CF08B3541 681 | :102A80000CF4805E659161341CF06B350CF4605E73 682 | :102A9000861B611171F3990B0895881BFCCF0E946E 683 | :102AA000911508F481E00895E89409C097FB3EF47D 684 | :102AB00090958095709561957F4F8F4F9F4F99238B 685 | :102AC000A9F0F92F96E9BB279395F6958795779509 686 | :102AD0006795B795F111F8CFFAF4BB0F11F460FFC9 687 | :102AE0001BC06F5F7F4F8F4F9F4F16C0882311F021 688 | :102AF00096E911C0772321F09EE8872F762F05C035 689 | :102B0000662371F096E8862F70E060E02AF09A95CF 690 | :102B1000660F771F881FDAF7880F9695879597F9C4 691 | :102B20000895990F0008550FAA0BE0E8FEEF16165E 692 | :102B30001706E807F907C0F012161306E407F507B1 693 | :102B400098F0621B730B840B950B39F40A2661F025 694 | :102B5000232B242B252B21F408950A2609F4A140C8 695 | :102B6000A6958FEF811D811D08950E94C8150C94B4 696 | :102B70003C160E942E1638F00E94351620F0952340 697 | :102B800011F00C9425160C942B1611240C9470162D 698 | :102B90000E944D1670F3959FC1F3950F50E0551F9D 699 | :102BA000629FF001729FBB27F00DB11D639FAA27A2 700 | :102BB000F00DB11DAA1F649F6627B00DA11D661FF1 701 | :102BC000829F2227B00DA11D621F739FB00DA11D12 702 | :102BD000621F839FA00D611D221F749F3327A00DCC 703 | :102BE000611D231F849F600D211D822F762F6A2F68 704 | :102BF00011249F5750409AF0F1F088234AF0EE0FCD 705 | :102C0000FF1FBB1F661F771F881F91505040A9F7F9 706 | :102C10009E3F510580F00C9425160C9470165F3F72 707 | :102C2000E4F3983ED4F3869577956795B795F79535 708 | :102C3000E7959F5FC1F7FE2B880F911D96958795AD 709 | :102C400097F9089599278827089597F99F6780E84D 710 | :102C500070E060E008959FEF80EC089500240A94EE 711 | :102C60001616170618060906089500240A94121667 712 | :102C70001306140605060895092E0394000C11F49A 713 | :102C8000882352F0BB0F40F4BF2B11F460FF04C047 714 | :102C90006F5F7F4F8F4F9F4F089557FD9058440FA0 715 | :102CA000551F59F05F3F71F04795880F97FB991FAB 716 | :102CB00061F09F3F79F08795089512161306140668 717 | :102CC000551FF2CF4695F1DF08C0161617061806F5 718 | :102CD000991FF1CF86957105610508940895E894D0 719 | :102CE000BB2766277727CB0197F908950E94B8166E 720 | :102CF000A59F900DB49F900DA49F800D911D112450 721 | :102D000008952F923F924F925F926F927F928F928F 722 | :102D10009F92AF92BF92CF92DF92EF92FF920F936A 723 | :102D20001F93CF93DF93CDB7DEB7CA1BDB0B0FB674 724 | :102D3000F894DEBF0FBECDBF09942A883988488831 725 | :102D40005F846E847D848C849B84AA84B984C884C7 726 | :102D5000DF80EE80FD800C811B81AA81B981CE0FBE 727 | :102D6000D11D0FB6F894DEBF0FBECDBFED010895A3 728 | :102D7000A29FB001B39FC001A39F700D811D1124BC 729 | :102D8000911DB29F700D811D1124911D089510E0B9 730 | :102D9000CDEFD0E004C0FE010E94870E2196CE3F09 731 | :082DA000D107C9F7F894FFCF39 732 | :102DA80000004D02800000000000AD0129017601FD 733 | :102DB80054016801F40100000000B30229019E02D9 734 | :102DC8006E028D028602304D210030443021000D04 735 | :042DD8000A002C00C1 736 | :00000001FF 737 | -------------------------------------------------------------------------------- /Arduino/Solinst-TestData/Solinst-TestData.ino: -------------------------------------------------------------------------------- 1 | void setup() { 2 | Serial.begin(9600); 3 | } 4 | 5 | void loop() { 6 | if (Serial.available() > 0) { 7 | int inByte = Serial.read(); 8 | 9 | Serial.println("22.1,62.8,21.6,48.3,18.5,10.563,2.354"); 10 | } 11 | delay(500); 12 | } 13 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | (This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.) 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/LICENSE-examples.md: -------------------------------------------------------------------------------- 1 | ##Software License Agreement (BSD-3 License) 2 | 3 | **Copyright (c) 2013, Stroud Water Research Center (SWRC) and the EnviroDIY Development Team.** 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 16 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/README.md: -------------------------------------------------------------------------------- 1 | Arduino-SDI-12 2 | ============== 3 | 4 | Arduino library for SDI-12 communications to a wide variety of environmental sensors. This library provides a general software solution, without requiring any additional hardware, to implement the SDI-12 communication protocol between an Arduino-based data logger and SDI12-enabled sensors. 5 | 6 | [SDI-12](http://www.sdi-12.org/) is an asynchronous, ASCII, serial communications protocol that was developed for intelligent sensory instruments that typically monitor environmental data. [Advantages of SDI-12](http://en.wikipedia.org/wiki/SDI-12) include the ability to use a single available data channel for many sensors. 7 | 8 | This project is part of the [EnviroDIY](http://envirodiy.org/) vision to create an open source hardware and software stack to deliver near real time environmental data from wireless sensor networks, such as the Arduino-compatible [EnviroDIY™ Mayfly Data Logger](http://envirodiy.org/mayfly/). 9 | 10 | ##Getting Started 11 | 12 | Read the [Arduino-SDI-12 wiki](https://github.com/StroudCenter/Arduino-SDI-12/wiki). 13 | 14 | ##Contribute 15 | Open an [issue](https://github.com/EnviroDIY/Arduino-SDI-12/issues) to suggest and discuss potential changes/additions. 16 | 17 | For power contributors: 18 | 19 | 1. Fork it! 20 | 2. Create your feature branch: `git checkout -b my-new-feature` 21 | 3. Commit your changes: `git commit -am 'Add some feature'` 22 | 4. Push to the branch: `git push origin my-new-feature` 23 | 5. Submit a pull request :D 24 | 25 | 26 | ##License 27 | The SDI12 library code is released under the GNU Lesser Public License (LGPL 2.1) -- See [LICENSE-examples.md](https://github.com/EnviroDIY/Arduino-SDI-12/blob/master/LICENSE) file for details. 28 | 29 | Example Arduino sketches are released under the BSD 3-Clause License -- See [LICENSE-examples.md](https://github.com/EnviroDIY/Arduino-SDI-12/blob/master/LICENSE.md) file for details. 30 | 31 | Documentation is licensed as [Creative Commons Attribution-ShareAlike 4.0](https://creativecommons.org/licenses/by-sa/4.0/) (CC-BY-SA) copyright. 32 | 33 | ##Credits 34 | [EnviroDIY](http://envirodiy.org/)™ is presented by the Stroud Water Research Center, with contributions from a community of enthusiasts sharing do-it-yourself ideas for environmental science and monitoring. 35 | 36 | [Kevin M. Smith](https://github.com/Kevin-M-Smith) is the primary developer of the Arduino-SDI-12 library, with input from [S. Hicks](https://github.com/s-hicks2) and many [other contributors](https://github.com/EnviroDIY/Arduino-SDI-12/graphs/contributors). 37 | 38 | This project has benefited from the support from the following funders: 39 | 40 | * National Science Foundation, awards [EAR-0724971](http://www.nsf.gov/awardsearch/showAward?AWD_ID=0724971), [EAR-1331856](http://www.nsf.gov/awardsearch/showAward?AWD_ID=1331856), [ACI-1339834](http://www.nsf.gov/awardsearch/showAward?AWD_ID=1339834) 41 | * Stroud Water Research Center endowment 42 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/SDI12.cpp: -------------------------------------------------------------------------------- 1 | /* ======================== Arduino SDI-12 ================================= 2 | 3 | Arduino library for SDI-12 communications to a wide variety of environmental 4 | sensors. This library provides a general software solution, without requiring 5 | any additional hardware. 6 | 7 | ======================== Attribution & License ============================= 8 | 9 | Copyright (C) 2013 Stroud Water Research Center 10 | Available at https://github.com/StroudCenter/Arduino-SDI-12 11 | 12 | Authored initially in August 2013 by: 13 | 14 | Kevin M. Smith (http://ethosengineering.org) 15 | Inquiries: SDI12@ethosengineering.org 16 | 17 | based on the SoftwareSerial library (formerly NewSoftSerial), authored by: 18 | ladyada (http://ladyada.net) 19 | Mikal Hart (http://www.arduiniana.org) 20 | Paul Stoffregen (http://www.pjrc.com) 21 | Garrett Mace (http://www.macetech.com) 22 | Brett Hagman (http://www.roguerobotics.com/) 23 | 24 | This library is free software; you can redistribute it and/or 25 | modify it under the terms of the GNU Lesser General Public 26 | License as published by the Free Software Foundation; either 27 | version 2.1 of the License, or (at your option) any later version. 28 | 29 | This library is distributed in the hope that it will be useful, 30 | but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 32 | Lesser General Public License for more details. 33 | 34 | You should have received a copy of the GNU Lesser General Public 35 | License along with this library; if not, write to the Free Software 36 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 37 | 38 | 39 | ==================== Notes on SDI-12, Specification v1.3 ====================== 40 | 41 | Overview: 42 | 43 | SDI-12 is a communications protocol that uses a single data wire to 44 | communicate with up to 62 uniquely addressed sensors. So long as each 45 | sensor supports SDI-12, mixed sensor types can appear on the same data 46 | bus. Each address is a single character. The valid ranges are 0-9, a-z, 47 | and A-Z. Only the datalogger can initiate communications on the data 48 | bus. 49 | 50 | It does so by pulling the data line into a 5v state for at least 12 51 | milliseconds to wake up all the sensors, before returning the line into 52 | a 0v state for 8 milliseconds announce an outgoing command. The command 53 | contains both the action to be taken, and the address of the device who 54 | should respond. If there is a sensor on the bus with that address, it is 55 | responsible for responding to the command. Sensors should ignore 56 | commands that were not issued to them, and should return to a sleep 57 | state until the datalogger again issues the wakeup sequence. 58 | 59 | Physical Connections: 1 data line (0v - 5.5v) 60 | 1 12v power line (9.6v - 16v) 61 | 1 ground line 62 | 63 | Baud Rate: 1200 bits per second 64 | 65 | Data Frame Format: 10 bits per data frame 66 | 1 start bit 67 | 7 data bits (least significant bit first) 68 | 1 even parity bit 69 | 1 stop bit 70 | 71 | Data Line: SDI-12 communication uses a single 72 | bi-directional data line 73 | with three-state, inverse logic. 74 | 75 | LINE CONDITION | BINARY STATE | VOLTAGE RANGE 76 | ----------------------------------------------- 77 | marking 1 -0.5 to 1.0 volts 78 | spacing 0 3.5 to 5.5 volts 79 | transition undefined 1.0 to 3.5 volts 80 | 81 | _____ _____ _____ _____ _____ spacing 82 | 5v | | | | | | | | | | 83 | | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | transition 84 | Ov___| |_____| |_____| |_____| |_____| |___ marking 85 | 86 | 87 | For more information, and for a list of commands and responses, please see 88 | SDI-12.org, official site of the SDI-12 Support Group. 89 | 90 | 91 | ==================== Code Organization ====================== 92 | 0. Includes, Defines, & Variable Declarations 93 | 1. Buffer Setup 94 | 2. Data Line States, Overview of Interrupts 95 | 3. Constructor, Destructor, SDI12.begin(), and SDI12.end() 96 | 4. Waking up, and talking to, the sensors. 97 | 5. Reading from the SDI-12 object. available(), peek(), read(), flush() 98 | 6. Using more than one SDI-12 object, isActive() and setActive(). 99 | 7. Interrupt Service Routine (getting the data into the buffer) 100 | 101 | =========== 0. Includes, Defines, & Variable Declarations ============= 102 | 103 | 0.1 - Include the header file for this library. 104 | 0.2 - defines the size of the buffer 105 | 0.3 - defines value for DISABLED state (see section 2) 106 | 0.4 - defines value for ENABLED state (not used, reserved for future) 107 | 0.5 - defines value for DISABLED state (see section 2) 108 | 0.6 - defines value for TRANSMITTING state (see section 2) 109 | 0.7 - defines value for LISTENING state 110 | 0.8 - defines value for the spacing of bits. 111 | 1200 bits per second implies 833 microseconds per bit. 112 | 830 seems to be a reliable value given the overhead of the call. 113 | 0.9 - holds a custom value that indicates a 114 | TIMEOUT has occurred from parseInt() or parseFloat(). This should not be set to 115 | a possible data value. 116 | 117 | 0.10 - a static pointer to the active object. See section 6. 118 | 0.11 - a reference to the data pin, used throughout the library 119 | 0.12 - holds the buffer overflow status 120 | 121 | */ 122 | 123 | #include // 0.1 header file for this library 124 | 125 | #define _BUFFER_SIZE 64 // 0.2 max RX buffer size 126 | #define DISABLED 0 // 0.3 value for DISABLED state 127 | #define ENABLED 1 // 0.4 value for ENABLED state 128 | #define HOLDING 2 // 0.5 value for DISABLED state 129 | #define TRANSMITTING 3 // 0.6 value for TRANSMITTING state 130 | #define LISTENING 4 // 0.7 value for LISTENING state 131 | #define SPACING 830 // 0.8 bit timing in microseconds 132 | int TIMEOUT = -9999; // 0.9 value to return to indicate TIMEOUT 133 | 134 | SDI12 *SDI12::_activeObject = NULL; // 0.10 pointer to active SDI12 object 135 | uint8_t _dataPin; // 0.11 reference to the data pin 136 | bool _bufferOverflow; // 0.12 buffer overflow status 137 | 138 | /* =========== 1. Buffer Setup ============================================ 139 | 140 | The buffer is used to store characters from the SDI-12 data line. 141 | Characters are read into the buffer when an interrupt is received on the 142 | data line. The buffer uses a circular implementation with pointers to 143 | both the head and the tail. There is one buffer per instance of the 144 | SDI-12 object. This will consume a good deal of RAM, so be prudent in 145 | running multiple instances. 146 | 147 | For more information on circular buffers: 148 | http://en.wikipedia.org/wiki/Circular_buffer 149 | 150 | 1.1 - Define a maximum buffer size (in number of characters). Increasing 151 | the buffer size will use more RAM. If you exceed 256 characters, be sure 152 | to change the data type of the index to support the larger range of 153 | addresses. 154 | 155 | 1.2 - Create a character array of the specified size. 1.3 - Index to 156 | buffer head. (unsigned 8-bit integer, can map from 0-255) 1.4 - Index to 157 | buffer tail. (unsigned 8-bit integer, can map from 0-255) 158 | 159 | */ 160 | 161 | // See section 0 above. // 1.1 - max buffer size 162 | char _rxBuffer[_BUFFER_SIZE]; // 1.2 - buff for incoming 163 | uint8_t _rxBufferHead = 0; // 1.3 - index of buff head 164 | uint8_t _rxBufferTail = 0; // 1.4 - index of buff tail 165 | 166 | /* =========== 2. Data Line States =============================== 167 | 168 | The Arduino is responsible for managing communication with the sensors. 169 | Since all the data transfer happens on the same line, the state of the 170 | data line is very important. 171 | 172 | When the pin is in the HOLDING state, it is holding the line LOW so that 173 | interference does not unintentionally wake the sensors up. The interrupt 174 | is disabled for the dataPin, because we are not expecting any SDI-12 175 | traffic. In the TRANSMITTING state, we would like exclusive control of 176 | the Arduino, so we shut off all interrupts, and vary the voltage of the 177 | dataPin in order to wake up and send commands to the sensor. In the 178 | LISTENING state, we are waiting for a sensor to respond, so we drop the 179 | voltage level to LOW and relinquish control (INPUT). If we would like to 180 | disable all SDI-12 functionality, then we set the system to the DISABLED 181 | state, removing the interrupt associated with the dataPin. For 182 | predictability, we set the pin to a LOW level high impedance state 183 | (INPUT). 184 | 185 | State Interrupts Pin Mode Pin Level 186 | HOLDING Pin Disable OUTPUT LOW 187 | TRANSMITTING All Disable OUTPUT VARYING 188 | LISTENING All Enable INPUT LOW 189 | DISABLED Pin Disable INPUT LOW 190 | 191 | ------------------------------| Sequencing |------------------------------ 192 | 193 | Generally, this is acceptable. 194 | HOLDING --> TRANSMITTING --> LISTENING --> TRANSMITTING --> LISTENING --> 195 | 196 | If you have interference, you should force a hold, using forceHold(); 197 | HOLDING --> TRANSMITTING --> LISTENING --> done reading, forceHold(); HOLDING 198 | 199 | -------------------------| Function Descriptions |------------------------- 200 | 201 | 2.1 - Sets the proper state. This is a private function, and only used 202 | internally. It uses #define values of HOLDING, TRANSMITTING, LISTENING, 203 | and DISABLED to determine which state should be set. The grid above 204 | defines the settings applied in changing to each state. 205 | 206 | 207 | 2.2 - A public function which forces the line into a "holding" state. 208 | This is generally unneeded, but for deployments where interference is an 209 | issue, it should be used after all expected bytes have been returned 210 | from the sensor. 211 | 212 | ------------------------| Overview of Interrupts |------------------------- 213 | 214 | Some vocabulary: 215 | Registers: PCMSK0, PCMSK1, PCMSK2 :registers that enable or disable 216 | pin-change interrupts on individual pins 217 | 218 | PCICR : a register where the three least significant bits enable or 219 | disable pin change interrupts on a range of pins, i.e. 220 | {0,0,0,0,0,PCIE2,PCIE1,PCIE0}, where PCIE2 maps to PCMSK2, PCIE1 maps to 221 | PCMSK1, and PCIE0 maps to PCMSK0. 222 | 223 | noInterrupts() globally disables interrupts (of all types), while interrupts() 224 | globally enables interrupts (of all types), but they will only occur if 225 | the requisite registers are set (e.g. PCMSK and PCICR). 226 | 227 | --------------| What is an interrupt? 228 | An interrupt is a signal that causes the microcontroller to halt 229 | execution of the program, and perform a subroutine known as an interrupt 230 | handler or Interrupt Service Routine (ISR). After the ISR, program 231 | execution continues. This allows the microcontroller to efficiently 232 | handle a time-sensitive function such as receiving a burst of data on 233 | one of its pins, by not forcing the microcontroller to wait for the 234 | data. It can perform other tasks until the interrupt is called. 235 | 236 | Physically, interrupts take the form of signals on the pins of the 237 | microcontroller. To make the library generic, the dataPin responds to 238 | pin change interrupts which are available on all pins of the Arduino 239 | Uno, and a majority of pins on other variants. Pin change interrupts 240 | trigger an ISR on any change of state detected for a specified pin. 241 | 242 | Obviously, interrupts are not always desirable, so they can be 243 | controlled by manipulating registers. Registers are small 1-byte (8-bit) 244 | stores of memory directly accessible by processor. There is one register 245 | PCICR, which can enable and disable pin change interrupts for a range of 246 | pins at a single time. 247 | 248 | There are also three registers that store the state (enabled/disabled) of the 249 | pin change interrupts: PCMSK0, PCMSK1, and PCMSK2. Each bit stores a 1 250 | (enabled) or 0 (disabled). 251 | 252 | For example, PCMSK0 holds an 8 bits which represent: 253 | PCMSK0 {PCINT7, PCINT6, PCINT5, PCINT4, PCINT3, PCINT2, PCINT1, PCINT0} 254 | 255 | On an Arduino Uno, these map to: 256 | PCMSK0 {XTAL2, XTAL1, Pin 13, Pin 12, Pin 11, Pin 10, Pin 9, Pin 8} 257 | 258 | ==================================================| Enabling an interrupt. 259 | 260 | Initially, no interrupts are enabled, so PCMSK0 looks like: {00000000}. 261 | If we were to use pin 9 as the data pin, we would set the bit in the pin 262 | 9 position to 1, like so: {00000010}. 263 | 264 | To accomplish this, we can make use of some predefined macros. 265 | 266 | One macro "digitalPinToPCMSK" is defined in "pins_arduino.h" which 267 | allows us to quickly get the proper register (PCMSK0, PCMSK1, or PCMSK2) 268 | given the number of the Arduino pin. So when we write: 269 | digitalPinToPCMSK(9), the address of PCMSK0 is returned. We can use the 270 | dereferencing operator '*' to get the value of the address. 271 | 272 | That is, *digitalPinToPCMSK(9) returns: {00000000}. 273 | 274 | Another macro , "digitalPinToPCMSKbit" is also defined in 275 | "pins_arduino.h" and returns the position of the bit of interest within 276 | the PCMSK of interest. 277 | 278 | So when we write: digitalPinToPCMSKbit(9), the value returned is 1, 279 | because pin 9 is represented by the "1st bit" within PCMSK0, which has a 280 | zero-based index. That is: PCMSK { 7th bit, 6th bit, 5th bit, 4th bit, 281 | 3rd bit, 2nd bit, 1st bit, 0th bit } 282 | 283 | The leftward bit shift operator "<<" can then used to create a "mask". 284 | Masks are data that are used during bitwise operations to manipulate 285 | (enable / disable) one or more individual bits simultaneously. 286 | 287 | The syntax for the operator is (variable << number_of_bits). 288 | Some examples: 289 | byte a = 5; // binary: a = 00000101 290 | byte b = a << 4; // binary: b = 01010000 291 | 292 | So when we write: (1< (00000010) --> (00000100)... and so on. This 492 | functionality makes use of the '<<=' operator which stores the result of 493 | the bit-shift back into the left hand side. 494 | 495 | If the result of (out & mask) determines whether a 1 or 0 should be sent. 496 | Again, here inverse logic may lead to easy confusion. 497 | 498 | if(out & mask){ 499 | digitalWrite(_dataPin, LOW); 500 | } 501 | else{ 502 | digitalWrite(_dataPin, HIGH); 503 | } 504 | 505 | + 4.2.4 - Send the stop bit. The stop bit is always a '1', so we simply 506 | write the dataPin LOW for SPACING microseconds. 507 | 508 | 4.3 - sendCommand(String cmd) is a publicly accessible function that 509 | sends out a String byte by byte the command line. 510 | 511 | */ 512 | 513 | // 4.1 - this function wakes up the entire sensor bus 514 | void SDI12::wakeSensors(){ 515 | setState(TRANSMITTING); 516 | digitalWrite(_dataPin, HIGH); 517 | delayMicroseconds(12100); 518 | digitalWrite(_dataPin, LOW); 519 | delayMicroseconds(8400); 520 | } 521 | 522 | // 4.2 - this function writes a character out on the data line 523 | void SDI12::writeChar(uint8_t out) 524 | { 525 | 526 | out |= (parity_even_bit(out)<<7); // 4.2.1 - parity bit 527 | 528 | digitalWrite(_dataPin, HIGH); // 4.2.2 - start bit 529 | delayMicroseconds(SPACING); 530 | 531 | for (byte mask = 0x01; mask; mask<<=1){ // 4.2.3 - send payload 532 | if(out & mask){ 533 | digitalWrite(_dataPin, LOW); 534 | } 535 | else{ 536 | digitalWrite(_dataPin, HIGH); 537 | } 538 | delayMicroseconds(SPACING); 539 | } 540 | 541 | digitalWrite(_dataPin, LOW); // 4.2.4 - stop bit 542 | delayMicroseconds(SPACING); 543 | } 544 | 545 | // 4.3 - this function sends out the characters of the String cmd, one by one 546 | void SDI12::sendCommand(String cmd){ 547 | wakeSensors(); // wake up sensors 548 | for (int i = 0; i < cmd.length(); i++){ 549 | writeChar(cmd[i]); // write each characters 550 | } 551 | setState(LISTENING); // listen for reply 552 | } 553 | 554 | 555 | /* ============= 5. Reading from the SDI-12 object. =================== 556 | 557 | 5.1 - available() is a public function that returns the number of 558 | characters available in the buffer. 559 | 560 | To understand how: 561 | _rxBufferTail + _BUFFER_SIZE - _rxBufferHead) % _BUFFER_SIZE; 562 | accomplishes this task, we will use a few examples. 563 | 564 | To start take the buffer below that has _BUFFER_SIZE = 10. The 565 | message "abc" has been wrapped around (circular buffer). 566 | 567 | _rxBufferTail = 1 // points to the '-' after c 568 | _rxBufferHead = 8 // points to 'a' 569 | 570 | [ c ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ a ] [ b ] 571 | 572 | The number of available characters is (1 + 10 - 8) % 10 = 3 573 | 574 | The '%' or modulo operator finds the remainder of division of one number 575 | by another. In integer arithmetic 3 / 10 = 0, but has a remainder of 3. 576 | We can only get the remainder by using the the modulo '%'. 3 % 10 = 3. 577 | This next case demonstrates more clearly why the modulo is used. 578 | 579 | _rxBufferTail = 4 // points to the '-' after c 580 | _rxBufferHead = 1 // points to 'a' 581 | 582 | [ a ] [ b ] [ c ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] 583 | 584 | The number of available characters is (4 + 10 - 1) % 10 = 3 585 | 586 | If we did not use the modulo we would get either ( 4 + 10 - 1 ) = 13 587 | characters or ( 4 + 10 - 1 ) / 10 = 1 character. Obviously neither is 588 | correct. 589 | 590 | If there has been a buffer overflow, available() will return -1. 591 | 592 | 5.2 - peek() is a public function that allows the user to look at the 593 | character that is at the head of the buffer. Unlike read() it does not 594 | consume the character (i.e. the index addressed by _rxBufferHead is not 595 | changed). peek() returns -1 if there are no characters to show. 596 | 597 | 5.3 - flush() is a public function that clears the buffers contents by 598 | setting the index for both head and tail back to zero. 599 | 600 | 5.4 - read() returns the character at the current head in the buffer 601 | after incrementing the index of the buffer head. This action 'consumes' 602 | the character, meaning it can not be read from the buffer again. If you 603 | would rather see the character, but leave the index to head intact, you 604 | should use peek(); 605 | 606 | 5.5 - peekNextDigit() is called by the Stream class. It is overridden 607 | here to allow for a custom TIMEOUT value. The default value for the 608 | Stream class is to return 0. This makes distinguishing timeouts from 609 | true zero readings impossible. Therefore the default value has been 610 | set to -9999 in section 0 of the code. It is a public variable and 611 | can be changed dynamically within a program by calling: 612 | mySDI12.TIMEOUT = (int) newValue 613 | 614 | */ 615 | 616 | // 5.1 - reveals the number of characters available in the buffer 617 | int SDI12::available() 618 | { 619 | if(_bufferOverflow) return -1; 620 | return (_rxBufferTail + _BUFFER_SIZE - _rxBufferHead) % _BUFFER_SIZE; 621 | } 622 | 623 | // 5.2 - reveals the next character in the buffer without consuming 624 | int SDI12::peek() 625 | { 626 | if (_rxBufferHead == _rxBufferTail) return -1; // Empty buffer? If yes, -1 627 | return _rxBuffer[_rxBufferHead]; // Otherwise, read from "head" 628 | } 629 | 630 | // 5.3 - a public function that clears the buffer contents and 631 | // resets the status of the buffer overflow. 632 | void SDI12::flush() 633 | { 634 | _rxBufferHead = _rxBufferTail = 0; 635 | _bufferOverflow = false; 636 | } 637 | 638 | // 5.4 - reads in the next character from the buffer (and moves the index ahead) 639 | int SDI12::read() 640 | { 641 | _bufferOverflow = false; //reading makes room in the buffer 642 | if (_rxBufferHead == _rxBufferTail) return -1; // Empty buffer? If yes, -1 643 | uint8_t nextChar = _rxBuffer[_rxBufferHead]; // Otherwise, grab char at head 644 | _rxBufferHead = (_rxBufferHead + 1) % _BUFFER_SIZE; // increment head 645 | return nextChar; // return the char 646 | } 647 | 648 | // 5.5 - this function is called by the Stream class when parsing digits 649 | int SDI12::peekNextDigit() 650 | { 651 | int c; 652 | while (1) { 653 | c = timedPeek(); 654 | if (c < 0) return TIMEOUT; // timeout 655 | if (c == '-') return c; 656 | if (c >= '0' && c <= '9') return c; 657 | read(); // discard non-numeric 658 | } 659 | } 660 | 661 | /* ============= 6. Using more than one SDI-12 object. =================== 662 | 663 | This library is allows for multiple instances of itself running on 664 | different pins, however, you should use care. The instances DO NOT share 665 | a buffer, as they do in the multi-instance case for SoftwareSerial, so 666 | it will consume more RAM than you might expect. 667 | 668 | SDI-12 can support up to 62 sensors on a single pin/bus, so it is not 669 | necessary to use an instance for each sensor. 670 | 671 | Because we are using pin change interrupts there can only be one active 672 | object at a time (since this is the only reliable way to determine which 673 | pin the interrupt occurred on). The active object is the only object 674 | that will respond properly to interrupts. However promoting another 675 | instance to Active status does not automatically remove the interrupts 676 | on the other pin. For proper behavior it is recommended to use this 677 | pattern: 678 | 679 | mySDI12.forceHold(); 680 | myOtherSDI12.setActive(); 681 | 682 | Other notes: Promoting an object into the Active state will set it as 683 | HOLDING. See 6.1 for more information. 684 | 685 | Calling mySDI12.begin() will assert mySDI12 as the new active object, 686 | until another instance calls myOtherSDI12.begin() or 687 | myOtherSDI12.setActive(). 688 | 689 | Calling mySDI12.end() does NOT hand-off active status to another SDI-12 690 | instance. 691 | 692 | You can check on the active object by calling mySDI12.isActive(), which 693 | will return a boolean value TRUE if active or FALSE if inactive. 694 | 695 | 6.1 - a method for setting the current object as the active object. 696 | returns TRUE if the object was not formerly the active object and now 697 | is. returns 698 | 699 | Promoting an inactive to the active instance will start it in the 700 | HOLDING state and return TRUE. 701 | 702 | Otherwise, if the object is currently the active instance, it will 703 | remain unchanged and return FALSE. 704 | 705 | 6.2 - a method for checking if the object is the active object. Returns 706 | true if the object is currently the active object, false otherwise. 707 | 708 | */ 709 | 710 | // 6.1 - a method for setting the current object as the active object 711 | bool SDI12::setActive() 712 | { 713 | if (_activeObject != this) 714 | { 715 | setState(HOLDING); 716 | _activeObject = this; 717 | return true; 718 | } 719 | return false; 720 | } 721 | 722 | // 6.2 - a method for checking if this object is the active object 723 | bool SDI12::isActive() { return this == _activeObject; } 724 | 725 | 726 | /* ============== 7. Interrupt Service Routine =================== 727 | 728 | We have received an interrupt signal, what should we do? 729 | 730 | 7.1 - Passes off responsibility for the interrupt to the active object. 731 | 732 | 7.2 - This function quickly reads a new character from the data line in 733 | to the buffer. It takes place over a series of key steps. 734 | 735 | + 7.2.1 - Check for the start bit. If it is not there, interrupt may be 736 | from interference or an interrupt we are not interested in, so return. 737 | 738 | + 7.2.2 - Make space in memory for the new character "newChar". 739 | 740 | + 7.2.3 - Wait half of a SPACING to help center on the next bit. It will 741 | not actually be centered, or even approximately so until 742 | delayMicroseconds(SPACING) is called again. 743 | 744 | + 7.2.4 - For each of the 8 bits in the payload, read wether or not the 745 | line state is HIGH or LOW. We use a moving mask here, as was previously 746 | demonstrated in the writeByte() function. 747 | 748 | The loop runs from i=0x1 (hexadecimal notation for 00000001) to i<0x80 749 | (hexadecimal notation for 10000000). So the loop effectively uses the 750 | masks following masks: 00000001 751 | 00000010 752 | 00000100 753 | 00001000 754 | 00010000 755 | 00100000 756 | 01000000 and their inverses. 757 | 758 | Here we use an if / else structure that helps to balance the time it 759 | takes to either a HIGH vs a LOW, and helps maintain a constant timing. 760 | 761 | + 7.2.5 - Skip the parity bit. There is no error checking. 762 | 763 | + 7.2.6 - Skip the stop bit. 764 | 765 | + 7.2.7 - Check for an overflow. We do this by checking if advancing the 766 | tail would make it have the same index as the head (in a circular 767 | fashion). 768 | 769 | + 7.2.8 - Save the byte into the buffer if there has not been an 770 | overflow, and then advance the tail index. 771 | 772 | 7.3 - Check if the various interrupt vectors are defined. If they are 773 | the ISR is instructed to call _handleInterrupt() when they trigger. */ 774 | 775 | // 7.1 - Passes off responsibility for the interrupt to the active object. 776 | inline void SDI12::handleInterrupt(){ 777 | if (_activeObject) _activeObject->receiveChar(); 778 | } 779 | 780 | // 7.2 - Quickly reads a new character into the buffer. 781 | void SDI12::receiveChar() 782 | { 783 | if (digitalRead(_dataPin)) // 7.2.1 - Start bit? 784 | { 785 | uint8_t newChar = 0; // 7.2.2 - Make room for char. 786 | 787 | delayMicroseconds(SPACING/2); // 7.2.3 - Wait 1/2 SPACING 788 | 789 | for (uint8_t i=0x1; i<0x80; i <<= 1) // 7.2.4 - read the 7 data bits 790 | { 791 | delayMicroseconds(SPACING); 792 | uint8_t noti = ~i; 793 | if (!digitalRead(_dataPin)) 794 | newChar |= i; 795 | else 796 | newChar &= noti; 797 | } 798 | 799 | delayMicroseconds(SPACING); // 7.2.5 - Skip the parity bit. 800 | delayMicroseconds(SPACING); // 7.2.6 - Skip the stop bit. 801 | 802 | // 7.2.7 - Overflow? If not, proceed. 803 | if ((_rxBufferTail + 1) % _BUFFER_SIZE == _rxBufferHead) 804 | { _bufferOverflow = true; 805 | } else { // 7.2.8 - Save char, advance tail. 806 | _rxBuffer[_rxBufferTail] = newChar; 807 | _rxBufferTail = (_rxBufferTail + 1) % _BUFFER_SIZE; 808 | } 809 | } 810 | } 811 | 812 | //7.3 813 | #if defined(PCINT0_vect) 814 | ISR(PCINT0_vect){ SDI12::handleInterrupt(); } 815 | #endif 816 | 817 | #if defined(PCINT1_vect) 818 | ISR(PCINT1_vect){ SDI12::handleInterrupt(); } 819 | #endif 820 | 821 | #if defined(PCINT2_vect) 822 | ISR(PCINT2_vect){ SDI12::handleInterrupt(); } 823 | #endif 824 | 825 | #if defined(PCINT3_vect) 826 | ISR(PCINT3_vect){ SDI12::handleInterrupt(); } 827 | #endif 828 | 829 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/SDI12.h: -------------------------------------------------------------------------------- 1 | /* ======================== Arduino SDI-12 ================================= 2 | 3 | Arduino library for SDI-12 communications to a wide variety of environmental 4 | sensors. This library provides a general software solution, without requiring 5 | any additional hardware. 6 | 7 | ======================== Attribution & License ============================= 8 | 9 | Copyright (C) 2013 Stroud Water Research Center 10 | Available at https://github.com/StroudCenter/Arduino-SDI-12 11 | 12 | Authored initially in August 2013 by: 13 | 14 | Kevin M. Smith (http://ethosengineering.org) 15 | Inquiries: SDI12@ethosengineering.org 16 | 17 | based on the SoftwareSerial library (formerly NewSoftSerial), authored by: 18 | ladyada (http://ladyada.net) 19 | Mikal Hart (http://www.arduiniana.org) 20 | Paul Stoffregen (http://www.pjrc.com) 21 | Garrett Mace (http://www.macetech.com) 22 | Brett Hagman (http://www.roguerobotics.com/) 23 | 24 | This library is free software; you can redistribute it and/or 25 | modify it under the terms of the GNU Lesser General Public 26 | License as published by the Free Software Foundation; either 27 | version 2.1 of the License, or (at your option) any later version. 28 | 29 | This library is distributed in the hope that it will be useful, 30 | but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 32 | Lesser General Public License for more details. 33 | 34 | You should have received a copy of the GNU Lesser General Public 35 | License along with this library; if not, write to the Free Software 36 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 37 | */ 38 | 39 | #ifndef SDI12_h 40 | #define SDI12_h 41 | 42 | // Import Required Libraries 43 | #include // interrupt handling 44 | #include // optimized parity bit handling 45 | #include // integer types library 46 | #include // Arduino core library 47 | #include // Arduino Stream library 48 | 49 | class SDI12 : public Stream 50 | { 51 | protected: 52 | int peekNextDigit(); // override of Stream equivalent to allow custom TIMEOUT 53 | private: 54 | static SDI12 *_activeObject; // static pointer to active SDI12 instance 55 | void setState(uint8_t state); // sets the state of the SDI12 objects 56 | void wakeSensors(); // used to wake up the SDI12 bus 57 | void writeChar(uint8_t out); // used to send a char out on the data line 58 | void receiveChar(); // used by the ISR to grab a char from data line 59 | 60 | public: 61 | int TIMEOUT; 62 | SDI12(uint8_t dataPin); // constructor 63 | ~SDI12(); // destructor 64 | void begin(); // enable SDI-12 object 65 | void end(); // disable SDI-12 object 66 | 67 | void forceHold(); // sets line state to HOLDING 68 | void sendCommand(String cmd); // sends the String cmd out on the data line 69 | 70 | int available(); // returns the number of bytes available in buffer 71 | int peek(); // reveals next byte in buffer without consuming 72 | int read(); // returns next byte in the buffer (consumes) 73 | void flush(); // clears the buffer 74 | virtual size_t write(uint8_t byte){}; // dummy function required to inherit from Stream 75 | 76 | bool setActive(); // set this instance as the active SDI-12 instance 77 | bool isActive(); // check if this instance is active 78 | 79 | static inline void handleInterrupt(); // intermediary used by the ISR 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/examples/a_wild_card/a_wild_card.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ######################## 3 | # OVERVIEW # 4 | ######################## 5 | 6 | Example A: Using the wildcard. 7 | 8 | This is a simple demonstration of the SDI-12 library for Arduino. 9 | It requests information about the attached sensor, including its address and manufacturer info. 10 | 11 | ######################### 12 | # THE CIRCUIT # 13 | ######################### 14 | 15 | You should not have more than one SDI-12 device attached for this example. 16 | 17 | See: 18 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_no_usb.png 19 | or 20 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb.png 21 | 22 | ########################### 23 | # COMPATIBILITY # 24 | ########################### 25 | 26 | This library requires the use of pin change interrupts (PCINT). 27 | Not all Arduino boards have the same pin capabilities. 28 | The known compatibile pins for common variants are shown below. 29 | 30 | Arduino Uno: All pins. 31 | 32 | Arduino Mega or Mega 2560: 33 | 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), 34 | A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69). 35 | 36 | Arduino Leonardo: 37 | 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 38 | 39 | ######################### 40 | # RESOURCES # 41 | ######################### 42 | 43 | Written by Kevin M. Smith in 2013. 44 | Contact: SDI12@ethosengineering.org 45 | 46 | The SDI-12 specification is available at: http://www.sdi-12.org/ 47 | The library is available at: https://github.com/StroudCenter/Arduino-SDI-12 48 | */ 49 | 50 | #include 51 | 52 | #define DATAPIN 9 // change to the proper pin 53 | SDI12 mySDI12(DATAPIN); 54 | 55 | /* 56 | '?' is a wildcard character which asks any and all sensors to respond 57 | 'I' indicates that the command wants information about the sensor 58 | '!' finishes the command 59 | */ 60 | String myCommand = "?I!"; 61 | 62 | void setup(){ 63 | Serial.begin(9600); 64 | mySDI12.begin(); 65 | } 66 | 67 | void loop(){ 68 | mySDI12.sendCommand(myCommand); 69 | delay(300); // wait a while for a response 70 | while(mySDI12.available()){ // write the response to the screen 71 | Serial.write(mySDI12.read()); 72 | } 73 | delay(3000); // print again in three seconds 74 | } 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/examples/b_address_change/b_address_change.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ######################## 3 | # OVERVIEW # 4 | ######################## 5 | 6 | Example B: Changing the address of a sensor. 7 | 8 | This is a simple demonstration of the SDI-12 library for arduino. 9 | It discovers the address of the attached sensor and allows you to change it. 10 | 11 | ######################### 12 | # THE CIRCUIT # 13 | ######################### 14 | 15 | The circuit: You should not have more than one SDI-12 device attached for this example. 16 | 17 | See: 18 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_no_usb.png 19 | or 20 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb.png 21 | 22 | ########################### 23 | # COMPATIBILITY # 24 | ########################### 25 | 26 | This library requires the use of pin change interrupts (PCINT). 27 | Not all Arduino boards have the same pin capabilities. 28 | The known compatibile pins for common variants are shown below. 29 | 30 | Arduino Uno: All pins. 31 | 32 | Arduino Mega or Mega 2560: 33 | 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), 34 | A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69). 35 | 36 | Arduino Leonardo: 37 | 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 38 | 39 | ######################### 40 | # RESOURCES # 41 | ######################### 42 | 43 | Written by Kevin M. Smith in 2013. 44 | Contact: SDI12@ethosengineering.org 45 | 46 | The SDI-12 specification is available at: http://www.sdi-12.org/ 47 | The library is available at: https://github.com/StroudCenter/Arduino-SDI-12 48 | */ 49 | 50 | 51 | #include 52 | 53 | #define DATAPIN 9 // change to the proper pin 54 | SDI12 mySDI12(DATAPIN); 55 | 56 | String myCommand = ""; // empty to start 57 | char oldAddress = '!'; // invalid address as placeholder 58 | 59 | void setup(){ 60 | Serial.begin(9600); 61 | mySDI12.begin(); 62 | } 63 | 64 | void loop(){ 65 | boolean found = false; // have we identified the sensor yet? 66 | 67 | for(byte i = '0'; i <= '9'; i++){ // scan address space 0-9 68 | if(found) break; 69 | if(checkActive(i)){ 70 | found = true; 71 | oldAddress = i; 72 | } 73 | } 74 | 75 | for(byte i = 'a'; i <= 'z'; i++){ // scan address space a-z 76 | if(found) break; 77 | if(checkActive(i)){ 78 | found = true; 79 | oldAddress = i; 80 | } 81 | } 82 | 83 | for(byte i = 'A'; i <= 'Z'; i++){ // scan address space A-Z 84 | if(found) break; 85 | if(checkActive(i)){ 86 | found = true; 87 | oldAddress = i; 88 | } 89 | } 90 | 91 | if(!found){ 92 | Serial.println("No sensor detected. Check physical connections."); // couldn't find a sensor. check connections.. 93 | } 94 | else{ 95 | Serial.print("Sensor active at address "); // found a sensor! 96 | Serial.print(oldAddress); 97 | Serial.println("."); 98 | 99 | Serial.println("Enter new address."); // prompt for a new address 100 | while(!Serial.available()); 101 | char newAdd= Serial.read(); 102 | 103 | // wait for valid response 104 | while( ((newAdd<'0') || (newAdd>'9')) && ((newAdd<'a') || (newAdd>'z')) && ((newAdd<'A') || (newAdd>'Z'))){ 105 | if(!(newAdd =='\n') || (newAdd =='\r') || (newAdd ==' ')) { 106 | Serial.println("Not a valid address. Please enter '0'-'9', 'a'-'A', or 'z'-'Z'."); 107 | } 108 | while(!Serial.available()); 109 | newAdd = Serial.read(); 110 | } 111 | 112 | /* the syntax of the change address command is: 113 | [currentAddress]A[newAddress]! */ 114 | 115 | Serial.println("Readdressing sensor."); 116 | myCommand = ""; 117 | myCommand += (char) oldAddress; 118 | myCommand += "A"; 119 | myCommand += (char) newAdd; 120 | myCommand += "!"; 121 | mySDI12.sendCommand(myCommand); 122 | 123 | /* wait for the response then throw it away by 124 | clearing the buffer with flush() */ 125 | delay(300); 126 | mySDI12.flush(); 127 | 128 | Serial.println("Success. Rescanning for verification."); 129 | } 130 | } 131 | 132 | 133 | boolean checkActive(byte i){ // this checks for activity at a particular address 134 | Serial.print("Checking address "); 135 | Serial.print((char)i); 136 | Serial.print("..."); 137 | myCommand = ""; 138 | myCommand += (char) i; // sends basic 'acknowledge' command [address][!] 139 | myCommand += "!"; 140 | 141 | for(int j = 0; j < 3; j++){ // goes through three rapid contact attempts 142 | mySDI12.sendCommand(myCommand); 143 | if(mySDI12.available()>1) break; 144 | delay(30); 145 | } 146 | if(mySDI12.available()>2){ // if it hears anything it assumes the address is occupied 147 | Serial.println("Occupied"); 148 | mySDI12.flush(); 149 | return true; 150 | } 151 | else { 152 | Serial.println("Vacant"); // otherwise it is vacant. 153 | mySDI12.flush(); 154 | } 155 | return false; 156 | } 157 | 158 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/examples/c_check_all_addresses/c_check_all_addresses.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ######################## 3 | # OVERVIEW # 4 | ######################## 5 | 6 | Example C: Checks all addresses for active sensors, and prints their status to the serial port. 7 | 8 | This is a simple demonstration of the SDI-12 library for Arduino. 9 | 10 | It discovers the address of all sensors active on a single bus. 11 | 12 | Each sensor should have a unique address already - if not, multiple sensors may respond simultaenously 13 | to the same request and the output will not be readable by the Arduino. 14 | 15 | To address a sensor, please see Example B: b_address_change.ino 16 | 17 | ######################### 18 | # THE CIRCUIT # 19 | ######################### 20 | 21 | You may use one or more pre-adressed sensors. 22 | 23 | See: 24 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_usb_multiple_sensors.png 25 | or 26 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb_multiple_sensors.png 27 | 28 | ########################### 29 | # COMPATIBILITY # 30 | ########################### 31 | 32 | This library requires the use of pin change interrupts (PCINT). 33 | Not all Arduino boards have the same pin capabilities. 34 | The known compatibile pins for common variants are shown below. 35 | 36 | Arduino Uno: All pins. 37 | 38 | Arduino Mega or Mega 2560: 39 | 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), 40 | A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69). 41 | 42 | Arduino Leonardo: 43 | 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 44 | 45 | ######################### 46 | # RESOURCES # 47 | ######################### 48 | 49 | Written by Kevin M. Smith in 2013. 50 | Contact: SDI12@ethosengineering.org 51 | 52 | The SDI-12 specification is available at: http://www.sdi-12.org/ 53 | The library is available at: https://github.com/StroudCenter/Arduino-SDI-12 54 | */ 55 | 56 | 57 | #include 58 | 59 | #define DATAPIN 9 // change to the proper pin 60 | SDI12 mySDI12(DATAPIN); 61 | 62 | // keeps track of active addresses 63 | // each bit represents an address: 64 | // 1 is active (taken), 0 is inactive (available) 65 | // setTaken('A') will set the proper bit for sensor 'A' 66 | // set 67 | byte addressRegister[8] = { 68 | 0B00000000, 69 | 0B00000000, 70 | 0B00000000, 71 | 0B00000000, 72 | 0B00000000, 73 | 0B00000000, 74 | 0B00000000, 75 | 0B00000000 76 | }; 77 | 78 | 79 | void setup(){ 80 | Serial.begin(9600); 81 | mySDI12.begin(); 82 | delay(500); // allow things to settle 83 | 84 | /* 85 | Quickly Scan the Address Space 86 | */ 87 | 88 | for(byte i = '0'; i <= '9'; i++) if(checkActive(i)) setTaken(i); // scan address space 0-9 89 | 90 | for(byte i = 'a'; i <= 'z'; i++) if(checkActive(i)) setTaken(i); // scan address space a-z 91 | 92 | for(byte i = 'A'; i <= 'Z'; i++) if(checkActive(i)) setTaken(i); // scan address space A-Z 93 | 94 | /* 95 | For each active sensor, have it print it's current information. 96 | */ 97 | 98 | // scan address space 0-9 99 | for(char i = '0'; i <= '9'; i++) if(isTaken(i)){ 100 | Serial.print("Sensor "); 101 | Serial.print(i); 102 | Serial.print(":"); 103 | printInfo(i); 104 | Serial.println(); 105 | } 106 | 107 | // scan address space a-z 108 | for(char i = 'a'; i <= 'z'; i++) if(isTaken(i)){ 109 | Serial.print("Sensor "); 110 | Serial.print(i); 111 | Serial.print(": "); 112 | printInfo(i); 113 | Serial.println(); 114 | } 115 | 116 | // scan address space A-Z 117 | for(char i = 'A'; i <= 'Z'; i++) if(isTaken(i)){ 118 | Serial.print("Sensor "); 119 | Serial.print(i); 120 | Serial.print(":"); 121 | printInfo(i); 122 | Serial.println(); 123 | }; 124 | } 125 | 126 | 127 | // this checks for activity at a particular address 128 | // expects a char, '0'-'9', 'a'-'z', or 'A'-'Z' 129 | boolean checkActive(char i){ 130 | Serial.print("Checking address "); 131 | Serial.print(i); 132 | Serial.print("..."); 133 | String myCommand = ""; 134 | myCommand = ""; 135 | myCommand += (char) i; // sends basic 'acknowledge' command [address][!] 136 | myCommand += "!"; 137 | 138 | for(int j = 0; j < 3; j++){ // goes through three rapid contact attempts 139 | mySDI12.sendCommand(myCommand); 140 | if(mySDI12.available()>1) break; 141 | delay(30); 142 | } 143 | if(mySDI12.available()>2){ // if it hears anything it assumes the address is occupied 144 | Serial.println("Occupied"); 145 | mySDI12.flush(); 146 | return true; 147 | } 148 | else { 149 | Serial.println("Vacant"); // otherwise it is vacant. 150 | mySDI12.flush(); 151 | } 152 | return false; 153 | } 154 | 155 | 156 | // this sets the bit in the proper location within the addressRegister 157 | // to record that the sensor is active and the address is taken. 158 | boolean setTaken(byte i){ 159 | boolean initStatus = isTaken(i); 160 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 161 | byte j = i / 8; // byte # 162 | byte k = i % 8; // bit # 163 | addressRegister[j] |= (1 << k); 164 | return !initStatus; // return false if already taken 165 | } 166 | 167 | // THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL. 168 | // this unsets the bit in the proper location within the addressRegister 169 | // to record that the sensor is active and the address is taken. 170 | boolean setVacant(byte i){ 171 | boolean initStatus = isTaken(i); 172 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 173 | byte j = i / 8; // byte # 174 | byte k = i % 8; // bit # 175 | addressRegister[j] &= ~(1 << k); 176 | return initStatus; // return false if already vacant 177 | } 178 | 179 | 180 | // this quickly checks if the address has already been taken by an active sensor 181 | boolean isTaken(byte i){ 182 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 183 | byte j = i / 8; // byte # 184 | byte k = i % 8; // bit # 185 | return addressRegister[j] & (1<1) break; 199 | if(mySDI12.available()) mySDI12.read(); 200 | } 201 | 202 | mySDI12.read(); //consume sensor address (you can keep it if you'd like) 203 | 204 | while(mySDI12.available()){ 205 | Serial.write(mySDI12.read()); 206 | delay(5); 207 | } 208 | } 209 | 210 | // converts allowable address characters '0'-'9', 'a'-'z', 'A'-'Z', 211 | // to a decimal number between 0 and 61 (inclusive) to cover the 62 possible addresses 212 | byte charToDec(char i){ 213 | if((i >= '0') && (i <= '9')) return i - '0'; 214 | if((i >= 'a') && (i <= 'z')) return i - 'a' + 10; 215 | if((i >= 'A') && (i <= 'Z')) return i - 'A' + 37; 216 | } 217 | 218 | // THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL. 219 | // maps a decimal number between 0 and 61 (inclusive) to 220 | // allowable address characters '0'-'9', 'a'-'z', 'A'-'Z', 221 | char decToChar(byte i){ 222 | if((i >= 0) && (i <= 9)) return i + '0'; 223 | if((i >= 10) && (i <= 36)) return i + 'a' - 10; 224 | if((i >= 37) && (i <= 62)) return i + 'A' - 37; 225 | } 226 | 227 | void loop(){} // this sketch does not loop 228 | 229 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/examples/d_simple_logger/d_simple_logger.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ######################## 3 | # OVERVIEW # 4 | ######################## 5 | Example D: Checks all addresses for active sensors, and logs data for each sensor every minute. 6 | 7 | This is a simple demonstration of the SDI-12 library for Arduino. 8 | 9 | It discovers the address of all sensors active on a single bus and takes measurements from them. 10 | 11 | Every SDI-12 device is different in the time it takes to take a measurement, and the amount of data it returns. 12 | 13 | This sketch will not serve every sensor type, but it will likely be helpful in getting you started. 14 | 15 | Each sensor should have a unique address already - if not, multiple sensors may respond simultaenously 16 | to the same request and the output will not be readable by the Arduino. 17 | 18 | To address a sensor, please see Example B: b_address_change.ino 19 | 20 | ######################### 21 | # THE CIRCUIT # 22 | ######################### 23 | 24 | You may use one or more pre-adressed sensors. 25 | 26 | See: 27 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_usb_multiple_sensors.png 28 | or 29 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb_multiple_sensors.png 30 | or 31 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_usb.png 32 | or 33 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb.png 34 | 35 | ########################### 36 | # COMPATIBILITY # 37 | ########################### 38 | 39 | This library requires the use of pin change interrupts (PCINT). 40 | Not all Arduino boards have the same pin capabilities. 41 | The known compatibile pins for common variants are shown below. 42 | 43 | Arduino Uno: All pins. 44 | 45 | Arduino Mega or Mega 2560: 46 | 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), 47 | A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69). 48 | 49 | Arduino Leonardo: 50 | 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 51 | 52 | ######################### 53 | # RESOURCES # 54 | ######################### 55 | 56 | Written by Kevin M. Smith in 2013. 57 | Contact: SDI12@ethosengineering.org 58 | 59 | The SDI-12 specification is available at: http://www.sdi-12.org/ 60 | The library is available at: https://github.com/StroudCenter/Arduino-SDI-12 61 | */ 62 | 63 | 64 | #include 65 | 66 | #define DATAPIN 9 // change to the proper pin 67 | SDI12 mySDI12(DATAPIN); 68 | 69 | // keeps track of active addresses 70 | // each bit represents an address: 71 | // 1 is active (taken), 0 is inactive (available) 72 | // setTaken('A') will set the proper bit for sensor 'A' 73 | // set 74 | byte addressRegister[8] = { 75 | 0B00000000, 76 | 0B00000000, 77 | 0B00000000, 78 | 0B00000000, 79 | 0B00000000, 80 | 0B00000000, 81 | 0B00000000, 82 | 0B00000000 83 | }; 84 | 85 | 86 | void setup(){ 87 | Serial.begin(9600); 88 | mySDI12.begin(); 89 | delay(500); // allow things to settle 90 | 91 | Serial.println("Scanning all addresses, please wait..."); 92 | /* 93 | Quickly Scan the Address Space 94 | */ 95 | 96 | for(byte i = '0'; i <= '9'; i++) if(checkActive(i)) setTaken(i); // scan address space 0-9 97 | 98 | for(byte i = 'a'; i <= 'z'; i++) if(checkActive(i)) setTaken(i); // scan address space a-z 99 | 100 | for(byte i = 'A'; i <= 'Z'; i++) if(checkActive(i)) setTaken(i); // scan address space A-Z 101 | 102 | /* 103 | See if there are any active sensors. 104 | */ 105 | boolean found = false; 106 | 107 | for(byte i = 0; i < 62; i++){ 108 | if(isTaken(i)){ 109 | found = true; 110 | break; 111 | } 112 | } 113 | 114 | if(!found) { 115 | Serial.println("No sensors found, please check connections and restart the Arduino."); 116 | while(true); 117 | } // stop here 118 | 119 | Serial.println(); 120 | Serial.println("Time Elapsed (s), Sensor Address and ID, Measurement 1, Measurement 2, ... etc."); 121 | Serial.println("-------------------------------------------------------------------------------"); 122 | } 123 | 124 | void loop(){ 125 | 126 | // scan address space 0-9 127 | for(char i = '0'; i <= '9'; i++) if(isTaken(i)){ 128 | Serial.print(millis()/1000); 129 | Serial.print(","); 130 | printInfo(i); 131 | takeMeasurement(i); 132 | } 133 | 134 | // scan address space a-z 135 | for(char i = 'a'; i <= 'z'; i++) if(isTaken(i)){ 136 | Serial.print(millis()/1000); 137 | Serial.print(","); 138 | printInfo(i); 139 | takeMeasurement(i); 140 | } 141 | 142 | // scan address space A-Z 143 | for(char i = 'A'; i <= 'Z'; i++) if(isTaken(i)){ 144 | Serial.print(millis()/1000); 145 | Serial.print(","); 146 | printInfo(i); 147 | takeMeasurement(i); 148 | }; 149 | 150 | delay(10000); // wait ten seconds between measurement attempts. 151 | 152 | } 153 | 154 | void takeMeasurement(char i){ 155 | String command = ""; 156 | command += i; 157 | command += "M!"; // SDI-12 measurement command format [address]['M'][!] 158 | mySDI12.sendCommand(command); 159 | while(!mySDI12.available()>5); // wait for acknowlegement with format [address][ttt (3 char, seconds)][number of measurments available, 0-9] 160 | delay(100); 161 | 162 | mySDI12.read(); //consume address 163 | 164 | // find out how long we have to wait (in seconds). 165 | int wait = 0; 166 | wait += 100 * mySDI12.read()-'0'; 167 | wait += 10 * mySDI12.read()-'0'; 168 | wait += 1 * mySDI12.read()-'0'; 169 | 170 | mySDI12.read(); // ignore # measurements, for this simple examlpe 171 | mySDI12.read(); // ignore carriage return 172 | mySDI12.read(); // ignore line feed 173 | 174 | long timerStart = millis(); 175 | while((millis() - timerStart) > (1000 * wait)){ 176 | if(mySDI12.available()) break; //sensor can interrupt us to let us know it is done early 177 | } 178 | 179 | // in this example we will only take the 'DO' measurement 180 | mySDI12.flush(); 181 | command = ""; 182 | command += i; 183 | command += "D0!"; // SDI-12 command to get data [address][D][dataOption][!] 184 | mySDI12.sendCommand(command); 185 | while(!mySDI12.available()>1); // wait for acknowlegement 186 | delay(300); // let the data transfer 187 | printBufferToScreen(); 188 | mySDI12.flush(); 189 | } 190 | 191 | void printBufferToScreen(){ 192 | String buffer = ""; 193 | mySDI12.read(); // consume address 194 | while(mySDI12.available()){ 195 | char c = mySDI12.read(); 196 | if(c == '+' || c == '-'){ 197 | buffer += ','; 198 | if(c == '-') buffer += '-'; 199 | } 200 | else { 201 | buffer += c; 202 | } 203 | delay(100); 204 | } 205 | Serial.print(buffer); 206 | } 207 | 208 | 209 | // this checks for activity at a particular address 210 | // expects a char, '0'-'9', 'a'-'z', or 'A'-'Z' 211 | boolean checkActive(char i){ 212 | 213 | String myCommand = ""; 214 | myCommand = ""; 215 | myCommand += (char) i; // sends basic 'acknowledge' command [address][!] 216 | myCommand += "!"; 217 | 218 | for(int j = 0; j < 3; j++){ // goes through three rapid contact attempts 219 | mySDI12.sendCommand(myCommand); 220 | if(mySDI12.available()>1) break; 221 | delay(30); 222 | } 223 | if(mySDI12.available()>2){ // if it hears anything it assumes the address is occupied 224 | mySDI12.flush(); 225 | return true; 226 | } 227 | else { // otherwise it is vacant. 228 | mySDI12.flush(); 229 | } 230 | return false; 231 | } 232 | 233 | 234 | // this sets the bit in the proper location within the addressRegister 235 | // to record that the sensor is active and the address is taken. 236 | boolean setTaken(byte i){ 237 | boolean initStatus = isTaken(i); 238 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 239 | byte j = i / 8; // byte # 240 | byte k = i % 8; // bit # 241 | addressRegister[j] |= (1 << k); 242 | return !initStatus; // return false if already taken 243 | } 244 | 245 | // THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL. 246 | // this unsets the bit in the proper location within the addressRegister 247 | // to record that the sensor is active and the address is taken. 248 | boolean setVacant(byte i){ 249 | boolean initStatus = isTaken(i); 250 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 251 | byte j = i / 8; // byte # 252 | byte k = i % 8; // bit # 253 | addressRegister[j] &= ~(1 << k); 254 | return initStatus; // return false if already vacant 255 | } 256 | 257 | 258 | // this quickly checks if the address has already been taken by an active sensor 259 | boolean isTaken(byte i){ 260 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 261 | byte j = i / 8; // byte # 262 | byte k = i % 8; // bit # 263 | return addressRegister[j] & (1<1) break; 277 | if(mySDI12.available()) mySDI12.read(); 278 | } 279 | 280 | while(mySDI12.available()){ 281 | char c = mySDI12.read(); 282 | if((c!='\n') && (c!='\r')) Serial.write(c); 283 | delay(5); 284 | } 285 | } 286 | 287 | // converts allowable address characters '0'-'9', 'a'-'z', 'A'-'Z', 288 | // to a decimal number between 0 and 61 (inclusive) to cover the 62 possible addresses 289 | byte charToDec(char i){ 290 | if((i >= '0') && (i <= '9')) return i - '0'; 291 | if((i >= 'a') && (i <= 'z')) return i - 'a' + 10; 292 | if((i >= 'A') && (i <= 'Z')) return i - 'A' + 37; 293 | } 294 | 295 | // THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL. 296 | // maps a decimal number between 0 and 61 (inclusive) to 297 | // allowable address characters '0'-'9', 'a'-'z', 'A'-'Z', 298 | char decToChar(byte i){ 299 | if((i >= 0) && (i <= 9)) return i + '0'; 300 | if((i >= 10) && (i <= 36)) return i + 'a' - 10; 301 | if((i >= 37) && (i <= 62)) return i + 'A' - 37; 302 | } 303 | 304 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/examples/e_simple_parsing/e_simple_parsing.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ######################## 3 | # OVERVIEW # 4 | ######################## 5 | 6 | Example E: This example demonstrates the ability to parse integers and floats from the buffer. 7 | 8 | It is based closely on example D, however, every other time it prints out data, it multiplies the data by a factor of 2. 9 | 10 | Time Elapsed (s), Sensor Address and ID, Measurement 1, Measurement 2, ... etc. 11 | ------------------------------------------------------------------------------- 12 | 6,c13SENSOR ATM 311,0.62 x 2 = 1.24,19.80 x 2 = 39.60 13 | 17,c13SENSOR ATM 311,0.62,19.7 14 | 29,c13SENSOR ATM 311,0.62 x 2 = 1.2419.70 x 2 = 39.40 15 | 41,c13SENSOR ATM 311,0.62,19.8 16 | 17 | This is a trivial and nonsensical example, but it does demonstrate the ability to manipulate incoming data. 18 | 19 | At this point in the example series, the most relavent function to study is printBufferToScreen(). 20 | 21 | Other notes: 22 | This is a simple demonstration of the SDI-12 library for Arduino. 23 | 24 | It discovers the address of all sensors active on a single bus and takes measurements from them. 25 | 26 | Every SDI-12 device is different in the time it takes to take a measurement, and the amount of data it returns. 27 | 28 | This sketch will not serve every sensor type, but it will likely be helpful in getting you started. 29 | 30 | Each sensor should have a unique address already - if not, multiple sensors may respond simultaenously 31 | to the same request and the output will not be readable by the Arduino. 32 | 33 | To address a sensor, please see Example B: b_address_change.ino 34 | 35 | ######################### 36 | # THE CIRCUIT # 37 | ######################### 38 | 39 | You may use one or more pre-adressed sensors. 40 | 41 | See: 42 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_usb_multiple_sensors.png 43 | or 44 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb_multiple_sensors.png 45 | or 46 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_usb.png 47 | or 48 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb.png 49 | 50 | ########################### 51 | # COMPATIBILITY # 52 | ########################### 53 | 54 | This library requires the use of pin change interrupts (PCINT). 55 | Not all Arduino boards have the same pin capabilities. 56 | The known compatibile pins for common variants are shown below. 57 | 58 | Arduino Uno: All pins. 59 | 60 | Arduino Mega or Mega 2560: 61 | 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), 62 | A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69). 63 | 64 | Arduino Leonardo: 65 | 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 66 | 67 | ######################### 68 | # RESOURCES # 69 | ######################### 70 | 71 | Written by Kevin M. Smith in 2013. 72 | Contact: SDI12@ethosengineering.org 73 | 74 | The SDI-12 specification is available at: http://www.sdi-12.org/ 75 | The library is available at: https://github.com/StroudCenter/Arduino-SDI-12 76 | */ 77 | 78 | 79 | #include 80 | 81 | #define DATAPIN 9 // change to the proper pin 82 | SDI12 mySDI12(DATAPIN); 83 | 84 | boolean flip = 1; // variable that alternates output type back and forth. 85 | 86 | // The code below alternates printing in non-parsed, and parsed mode. 87 | // 88 | // The parseInt() and parseFloat() functions will timeout if they do not 89 | // find a candidate INT or FLOAT. 90 | // 91 | // The value returned when a TIMEOUT is encountered 92 | // is set in SDI12.cpp by default to -9999. 93 | // 94 | // You can change the default setting directly: 95 | // mySDI12.TIMEOUT = (int) newValue 96 | // The value of TIMEOUT should not be a possible data value. 97 | // 98 | // You should always check for timeouts before interpreting data, as 99 | // shown in the example below. 100 | 101 | void printBufferToScreen(){ 102 | 103 | flip = !flip; // flip the switch 104 | 105 | if(flip){ // print out the buffer as a string, as in example D 106 | boolean firstPass = true; 107 | String buffer = ""; 108 | mySDI12.read(); // consume address 109 | while(mySDI12.available()){ 110 | char c = mySDI12.read(); 111 | if(c == '+' || c == '-'){ 112 | buffer += ','; 113 | if(c == '-') buffer += '-'; 114 | } 115 | else { 116 | buffer += c; 117 | } 118 | firstPass = false; 119 | delay(100); 120 | } 121 | Serial.print(buffer); 122 | } 123 | else { // parse buffer for floats and multiply by 2 before printing 124 | while(mySDI12.available()){ 125 | float that = mySDI12.parseFloat(); 126 | if(that != mySDI12.TIMEOUT){ //check for timeout 127 | float doubleThat = that * 2; 128 | Serial.print(","); 129 | Serial.print(that); 130 | Serial.print(" x 2 = "); 131 | Serial.print(doubleThat); 132 | } 133 | } 134 | Serial.println(); 135 | } 136 | } 137 | 138 | // keeps track of active addresses 139 | // each bit represents an address: 140 | // 1 is active (taken), 0 is inactive (available) 141 | // setTaken('A') will set the proper bit for sensor 'A' 142 | byte addressRegister[8] = { 143 | 0B00000000, 144 | 0B00000000, 145 | 0B00000000, 146 | 0B00000000, 147 | 0B00000000, 148 | 0B00000000, 149 | 0B00000000, 150 | 0B00000000 151 | }; 152 | 153 | 154 | void setup(){ 155 | Serial.begin(9600); 156 | mySDI12.begin(); 157 | delay(500); // allow things to settle 158 | 159 | Serial.println("Scanning all addresses, please wait..."); 160 | /* 161 | Quickly Scan the Address Space 162 | */ 163 | 164 | for(byte i = '0'; i <= '9'; i++) if(checkActive(i)) setTaken(i); // scan address space 0-9 165 | 166 | for(byte i = 'a'; i <= 'z'; i++) if(checkActive(i)) setTaken(i); // scan address space a-z 167 | 168 | for(byte i = 'A'; i <= 'Z'; i++) if(checkActive(i)) setTaken(i); // scan address space A-Z 169 | 170 | /* 171 | See if there are any active sensors. 172 | */ 173 | boolean found = false; 174 | 175 | for(byte i = 0; i < 62; i++){ 176 | if(isTaken(i)){ 177 | found = true; 178 | break; 179 | } 180 | } 181 | 182 | if(!found) { 183 | Serial.println("No sensors found, please check connections and restart the Arduino."); 184 | while(true); 185 | } // stop here 186 | 187 | Serial.println(); 188 | Serial.println("Time Elapsed (s), Sensor Address and ID, Measurement 1, Measurement 2, ... etc."); 189 | Serial.println("-------------------------------------------------------------------------------"); 190 | } 191 | 192 | void loop(){ 193 | 194 | // scan address space 0-9 195 | for(char i = '0'; i <= '9'; i++) if(isTaken(i)){ 196 | Serial.print(millis()/1000); 197 | Serial.print(","); 198 | printInfo(i); 199 | takeMeasurement(i); 200 | } 201 | 202 | // scan address space a-z 203 | for(char i = 'a'; i <= 'z'; i++) if(isTaken(i)){ 204 | Serial.print(millis()/1000); 205 | Serial.print(","); 206 | printInfo(i); 207 | takeMeasurement(i); 208 | } 209 | 210 | // scan address space A-Z 211 | for(char i = 'A'; i <= 'Z'; i++) if(isTaken(i)){ 212 | Serial.print(millis()/1000); 213 | Serial.print(","); 214 | printInfo(i); 215 | takeMeasurement(i); 216 | }; 217 | 218 | delay(10000); // wait ten seconds between measurement attempts. 219 | 220 | } 221 | 222 | void takeMeasurement(char i){ 223 | String command = ""; 224 | command += i; 225 | command += "M!"; // SDI-12 measurement command format [address]['M'][!] 226 | mySDI12.sendCommand(command); 227 | while(!mySDI12.available()>5); // wait for acknowlegement with format [address][ttt (3 char, seconds)][number of measurments available, 0-9] 228 | delay(100); 229 | 230 | mySDI12.read(); //consume address 231 | 232 | // find out how long we have to wait (in seconds). 233 | int wait = 0; 234 | wait += 100 * mySDI12.read()-'0'; 235 | wait += 10 * mySDI12.read()-'0'; 236 | wait += 1 * mySDI12.read()-'0'; 237 | 238 | mySDI12.read(); // ignore # measurements, for this simple examlpe 239 | mySDI12.read(); // ignore carriage return 240 | mySDI12.read(); // ignore line feed 241 | 242 | long timerStart = millis(); 243 | while((millis() - timerStart) > (1000 * wait)){ 244 | if(mySDI12.available()) break; //sensor can interrupt us to let us know it is done early 245 | } 246 | 247 | // in this example we will only take the 'DO' measurement 248 | mySDI12.flush(); 249 | command = ""; 250 | command += i; 251 | command += "D0!"; // SDI-12 command to get data [address][D][dataOption][!] 252 | mySDI12.sendCommand(command); 253 | while(!mySDI12.available()>1); // wait for acknowlegement 254 | delay(300); // let the data transfer 255 | printBufferToScreen(); 256 | mySDI12.flush(); 257 | } 258 | 259 | 260 | // this checks for activity at a particular address 261 | // expects a char, '0'-'9', 'a'-'z', or 'A'-'Z' 262 | boolean checkActive(char i){ 263 | 264 | String myCommand = ""; 265 | myCommand = ""; 266 | myCommand += (char) i; // sends basic 'acknowledge' command [address][!] 267 | myCommand += "!"; 268 | 269 | for(int j = 0; j < 3; j++){ // goes through three rapid contact attempts 270 | mySDI12.sendCommand(myCommand); 271 | if(mySDI12.available()>1) break; 272 | delay(30); 273 | } 274 | if(mySDI12.available()>2){ // if it hears anything it assumes the address is occupied 275 | mySDI12.flush(); 276 | return true; 277 | } 278 | else { // otherwise it is vacant. 279 | mySDI12.flush(); 280 | } 281 | return false; 282 | } 283 | 284 | 285 | // this sets the bit in the proper location within the addressRegister 286 | // to record that the sensor is active and the address is taken. 287 | boolean setTaken(byte i){ 288 | boolean initStatus = isTaken(i); 289 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 290 | byte j = i / 8; // byte # 291 | byte k = i % 8; // bit # 292 | addressRegister[j] |= (1 << k); 293 | return !initStatus; // return false if already taken 294 | } 295 | 296 | // THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL. 297 | // this unsets the bit in the proper location within the addressRegister 298 | // to record that the sensor is active and the address is taken. 299 | boolean setVacant(byte i){ 300 | boolean initStatus = isTaken(i); 301 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 302 | byte j = i / 8; // byte # 303 | byte k = i % 8; // bit # 304 | addressRegister[j] &= ~(1 << k); 305 | return initStatus; // return false if already vacant 306 | } 307 | 308 | 309 | // this quickly checks if the address has already been taken by an active sensor 310 | boolean isTaken(byte i){ 311 | i = charToDec(i); // e.g. convert '0' to 0, 'a' to 10, 'Z' to 61. 312 | byte j = i / 8; // byte # 313 | byte k = i % 8; // bit # 314 | return addressRegister[j] & (1<= '0') && (i <= '9')) return i - '0'; 338 | if((i >= 'a') && (i <= 'z')) return i - 'a' + 10; 339 | if((i >= 'A') && (i <= 'Z')) return i - 'A' + 37; 340 | } 341 | 342 | // THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL. 343 | // maps a decimal number between 0 and 61 (inclusive) to 344 | // allowable address characters '0'-'9', 'a'-'z', 'A'-'Z', 345 | char decToChar(byte i){ 346 | if((i >= 0) && (i <= 9)) return i + '0'; 347 | if((i >= 10) && (i <= 36)) return i + 'a' - 10; 348 | if((i >= 37) && (i <= 62)) return i + 'A' - 37; 349 | } 350 | 351 | 352 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/examples/e_terminal_window/e_terminal_window.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Example E: Using the Arduino as a command terminal for SDI-12 sensors. 3 | Edited by Ruben Kertesz for ISCO Nile 502 2/10/2016…//functions as terminal 4 | 5 | This is a simple demonstration of the SDI-12 library for Arduino. 6 | It's purpose is to allow a user to interact with an SDI-12 sensor directly, 7 | issuing commands through a serial terminal window. 8 | 9 | The SDI-12 specification is available at: http://www.sdi-12.org/ 10 | The master library is available at: https://github.com/StroudCenter/Arduino-SDI-12 11 | The forked library with additional example files is available at: https://github.com/rkertesz/Arduino-SDI-12 12 | 13 | The circuit: It is recommended that you not have more than one SDI-12 device attached for this example. 14 | 15 | See: 16 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_no_usb.png 17 | or 18 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb.png 19 | 20 | Written by Kevin M. Smith in 2013. 21 | Contact: SDI12@ethosengineering.org 22 | Extended by Ruben Kertesz in 2016 23 | Contact: github@emnet.net or @rinnamon on twitter 24 | */ 25 | 26 | 27 | #include 28 | 29 | #define DATAPIN 12 // change to the proper pin 30 | SDI12 mySDI12(DATAPIN); 31 | 32 | char inByte = 0; 33 | String sdiResponse = ""; 34 | String myCommand = ""; 35 | 36 | void setup(){ 37 | Serial.begin(9600); 38 | mySDI12.begin(); 39 | } 40 | 41 | void loop(){ 42 | if (Serial.available()) { 43 | inByte = Serial.read(); 44 | if((inByte!='\n') && (inByte!='\r')) { //read all values entered in terminal window before enter 45 | myCommand += inByte; 46 | delay(5); 47 | } 48 | } 49 | 50 | if(inByte == '\r'){ // once we press enter, send string to SDI sensor/probe 51 | inByte = 0; 52 | Serial.println(myCommand); 53 | mySDI12.sendCommand(myCommand); 54 | delay(30); // wait a while for a response 55 | 56 | while(mySDI12.available()){ // build a string of the response 57 | char c = mySDI12.read(); 58 | if((c!='\n') && (c!='\r')) { 59 | sdiResponse += c; 60 | delay(5); 61 | } 62 | } 63 | if (sdiResponse.length()>1) Serial.println(sdiResponse); //write the response to the screen 64 | 65 | mySDI12.flush(); //clear the line 66 | myCommand = ""; 67 | sdiResponse = ""; 68 | } 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/examples/f_basic_data_request/f_basic_data_request.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Example F: Basic data request. 3 | Edited by Ruben Kertesz for ISCO Nile 502 2/10/2016 4 | 5 | This is a simple demonstration of the SDI-12 library for Arduino. 6 | This is a very basic (stripped down) example where the user initiates a measurement 7 | and receives the results to a terminal window without typing numerous commands into 8 | the terminal. 9 | 10 | The SDI-12 specification is available at: http://www.sdi-12.org/ 11 | The library is available at: https://github.com/StroudCenter/Arduino-SDI-12 12 | The forked library with additional example files is available at: https://github.com/rkertesz/Arduino-SDI-12 13 | 14 | The circuit: You should not have more than one SDI-12 device attached for this example. 15 | 16 | See: 17 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/basic_setup_no_usb.png 18 | or 19 | https://raw.github.com/Kevin-M-Smith/SDI-12-Circuit-Diagrams/master/compat_setup_usb.png 20 | 21 | Written by Kevin M. Smith in 2013. 22 | Contact: SDI12@ethosengineering.org 23 | Extended by Ruben Kertesz in 2016 24 | Contact: github@emnet.net or @rinnamon on twitter 25 | */ 26 | 27 | 28 | #include 29 | 30 | #define DATAPIN 12 // change to the proper pin 31 | SDI12 mySDI12(DATAPIN); 32 | 33 | String sdiResponse = ""; 34 | String myCommand = ""; 35 | 36 | void setup() { 37 | Serial.begin(9600); 38 | mySDI12.begin(); 39 | } 40 | 41 | void loop() { 42 | do { // wait for a response from the serial terminal to do anything 43 | delay (30); 44 | } 45 | while (!Serial.available()); 46 | char nogo = Serial.read(); // simply hit enter in the terminal window or press send and 47 | // the characters get discarded but now the rest of the loop continues 48 | 49 | //first command to take a measurement 50 | myCommand = "0M!"; // change "0" to the correct address of the sensor 51 | Serial.println(myCommand); // echo command to terminal 52 | 53 | mySDI12.sendCommand(myCommand); 54 | delay(30); // wait a while for a response 55 | 56 | while (mySDI12.available()) { // build response string 57 | char c = mySDI12.read(); 58 | if ((c != '\n') && (c != '\r')) { 59 | sdiResponse += c; 60 | delay(5); 61 | } 62 | } 63 | if (sdiResponse.length() > 1) Serial.println(sdiResponse); //write the response to the screen 64 | mySDI12.flush(); 65 | 66 | 67 | delay(1000); // delay between taking reading and requesting data 68 | sdiResponse = ""; // clear the response string 69 | 70 | 71 | // next command to request data from last measurement 72 | myCommand = "0D0!"; // CHANGE "0" to appropriate address 73 | Serial.println(myCommand); // echo command to terminal 74 | 75 | mySDI12.sendCommand(myCommand); 76 | delay(30); // wait a while for a response 77 | 78 | while (mySDI12.available()) { // build string from response 79 | char c = mySDI12.read(); 80 | if ((c != '\n') && (c != '\r')) { 81 | sdiResponse += c; 82 | delay(5); 83 | } 84 | } 85 | if (sdiResponse.length() > 1) Serial.println(sdiResponse); //write the response to the screen 86 | mySDI12.flush(); 87 | 88 | //now go back to top and wait until user hits enter on terminal window 89 | } 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Arduino/libraries/Arduino-SDI-12/keywords.txt: -------------------------------------------------------------------------------- 1 | 2 | # Syntax Coloring Map for SDI12 when 3 | # using the Arduino IDE. 4 | 5 | ### Classes (KEYWORD1) 6 | 7 | SDI12 KEYWORD1 8 | 9 | ### Methods and Functions (KEYWORD2) 10 | 11 | begin KEYWORD2 12 | end KEYWORD2 13 | forceHold KEYWORD2 14 | sendCommand KEYWORD2 15 | available KEYWORD2 16 | peek KEYWORD2 17 | read KEYWORD2 18 | flush KEYWORD2 19 | setActive KEYWORD2 20 | isActive KEYWORD2 21 | 22 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/DHT.cpp: -------------------------------------------------------------------------------- 1 | /* DHT library 2 | 3 | MIT license 4 | written by Adafruit Industries 5 | */ 6 | 7 | #include "DHT.h" 8 | 9 | #define MIN_INTERVAL 2000 10 | 11 | DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) { 12 | _pin = pin; 13 | _type = type; 14 | #ifdef __AVR 15 | _bit = digitalPinToBitMask(pin); 16 | _port = digitalPinToPort(pin); 17 | #endif 18 | _maxcycles = microsecondsToClockCycles(1000); // 1 millisecond timeout for 19 | // reading pulses from DHT sensor. 20 | // Note that count is now ignored as the DHT reading algorithm adjusts itself 21 | // basd on the speed of the processor. 22 | } 23 | 24 | void DHT::begin(void) { 25 | // set up the pins! 26 | pinMode(_pin, INPUT_PULLUP); 27 | // Using this value makes sure that millis() - lastreadtime will be 28 | // >= MIN_INTERVAL right away. Note that this assignment wraps around, 29 | // but so will the subtraction. 30 | _lastreadtime = -MIN_INTERVAL; 31 | DEBUG_PRINT("Max clock cycles: "); DEBUG_PRINTLN(_maxcycles, DEC); 32 | } 33 | 34 | //boolean S == Scale. True == Fahrenheit; False == Celcius 35 | float DHT::readTemperature(bool S, bool force) { 36 | float f = NAN; 37 | 38 | if (read(force)) { 39 | switch (_type) { 40 | case DHT11: 41 | f = data[2]; 42 | if(S) { 43 | f = convertCtoF(f); 44 | } 45 | break; 46 | case DHT22: 47 | case DHT21: 48 | f = data[2] & 0x7F; 49 | f *= 256; 50 | f += data[3]; 51 | f *= 0.1; 52 | if (data[2] & 0x80) { 53 | f *= -1; 54 | } 55 | if(S) { 56 | f = convertCtoF(f); 57 | } 58 | break; 59 | } 60 | } 61 | return f; 62 | } 63 | 64 | float DHT::convertCtoF(float c) { 65 | return c * 1.8 + 32; 66 | } 67 | 68 | float DHT::convertFtoC(float f) { 69 | return (f - 32) * 0.55555; 70 | } 71 | 72 | float DHT::readHumidity(bool force) { 73 | float f = NAN; 74 | if (read()) { 75 | switch (_type) { 76 | case DHT11: 77 | f = data[0]; 78 | break; 79 | case DHT22: 80 | case DHT21: 81 | f = data[0]; 82 | f *= 256; 83 | f += data[1]; 84 | f *= 0.1; 85 | break; 86 | } 87 | } 88 | return f; 89 | } 90 | 91 | //boolean isFahrenheit: True == Fahrenheit; False == Celcius 92 | float DHT::computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit) { 93 | // Using both Rothfusz and Steadman's equations 94 | // http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml 95 | float hi; 96 | 97 | if (!isFahrenheit) 98 | temperature = convertCtoF(temperature); 99 | 100 | hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094)); 101 | 102 | if (hi > 79) { 103 | hi = -42.379 + 104 | 2.04901523 * temperature + 105 | 10.14333127 * percentHumidity + 106 | -0.22475541 * temperature*percentHumidity + 107 | -0.00683783 * pow(temperature, 2) + 108 | -0.05481717 * pow(percentHumidity, 2) + 109 | 0.00122874 * pow(temperature, 2) * percentHumidity + 110 | 0.00085282 * temperature*pow(percentHumidity, 2) + 111 | -0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2); 112 | 113 | if((percentHumidity < 13) && (temperature >= 80.0) && (temperature <= 112.0)) 114 | hi -= ((13.0 - percentHumidity) * 0.25) * sqrt((17.0 - abs(temperature - 95.0)) * 0.05882); 115 | 116 | else if((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0)) 117 | hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2); 118 | } 119 | 120 | return isFahrenheit ? hi : convertFtoC(hi); 121 | } 122 | 123 | boolean DHT::read(bool force) { 124 | // Check if sensor was read less than two seconds ago and return early 125 | // to use last reading. 126 | uint32_t currenttime = millis(); 127 | if (!force && ((currenttime - _lastreadtime) < 2000)) { 128 | return _lastresult; // return last correct measurement 129 | } 130 | _lastreadtime = currenttime; 131 | 132 | // Reset 40 bits of received data to zero. 133 | data[0] = data[1] = data[2] = data[3] = data[4] = 0; 134 | 135 | // Send start signal. See DHT datasheet for full signal diagram: 136 | // http://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf 137 | 138 | // Go into high impedence state to let pull-up raise data line level and 139 | // start the reading process. 140 | digitalWrite(_pin, HIGH); 141 | delay(250); 142 | 143 | // First set data line low for 20 milliseconds. 144 | pinMode(_pin, OUTPUT); 145 | digitalWrite(_pin, LOW); 146 | delay(20); 147 | 148 | uint32_t cycles[80]; 149 | { 150 | // Turn off interrupts temporarily because the next sections are timing critical 151 | // and we don't want any interruptions. 152 | InterruptLock lock; 153 | 154 | // End the start signal by setting data line high for 40 microseconds. 155 | digitalWrite(_pin, HIGH); 156 | delayMicroseconds(40); 157 | 158 | // Now start reading the data line to get the value from the DHT sensor. 159 | pinMode(_pin, INPUT_PULLUP); 160 | delayMicroseconds(10); // Delay a bit to let sensor pull data line low. 161 | 162 | // First expect a low signal for ~80 microseconds followed by a high signal 163 | // for ~80 microseconds again. 164 | if (expectPulse(LOW) == 0) { 165 | DEBUG_PRINTLN(F("Timeout waiting for start signal low pulse.")); 166 | _lastresult = false; 167 | return _lastresult; 168 | } 169 | if (expectPulse(HIGH) == 0) { 170 | DEBUG_PRINTLN(F("Timeout waiting for start signal high pulse.")); 171 | _lastresult = false; 172 | return _lastresult; 173 | } 174 | 175 | // Now read the 40 bits sent by the sensor. Each bit is sent as a 50 176 | // microsecond low pulse followed by a variable length high pulse. If the 177 | // high pulse is ~28 microseconds then it's a 0 and if it's ~70 microseconds 178 | // then it's a 1. We measure the cycle count of the initial 50us low pulse 179 | // and use that to compare to the cycle count of the high pulse to determine 180 | // if the bit is a 0 (high state cycle count < low state cycle count), or a 181 | // 1 (high state cycle count > low state cycle count). Note that for speed all 182 | // the pulses are read into a array and then examined in a later step. 183 | for (int i=0; i<80; i+=2) { 184 | cycles[i] = expectPulse(LOW); 185 | cycles[i+1] = expectPulse(HIGH); 186 | } 187 | } // Timing critical code is now complete. 188 | 189 | // Inspect pulses and determine which ones are 0 (high state cycle count < low 190 | // state cycle count), or 1 (high state cycle count > low state cycle count). 191 | for (int i=0; i<40; ++i) { 192 | uint32_t lowCycles = cycles[2*i]; 193 | uint32_t highCycles = cycles[2*i+1]; 194 | if ((lowCycles == 0) || (highCycles == 0)) { 195 | DEBUG_PRINTLN(F("Timeout waiting for pulse.")); 196 | _lastresult = false; 197 | return _lastresult; 198 | } 199 | data[i/8] <<= 1; 200 | // Now compare the low and high cycle times to see if the bit is a 0 or 1. 201 | if (highCycles > lowCycles) { 202 | // High cycles are greater than 50us low cycle count, must be a 1. 203 | data[i/8] |= 1; 204 | } 205 | // Else high cycles are less than (or equal to, a weird case) the 50us low 206 | // cycle count so this must be a zero. Nothing needs to be changed in the 207 | // stored data. 208 | } 209 | 210 | DEBUG_PRINTLN(F("Received:")); 211 | DEBUG_PRINT(data[0], HEX); DEBUG_PRINT(F(", ")); 212 | DEBUG_PRINT(data[1], HEX); DEBUG_PRINT(F(", ")); 213 | DEBUG_PRINT(data[2], HEX); DEBUG_PRINT(F(", ")); 214 | DEBUG_PRINT(data[3], HEX); DEBUG_PRINT(F(", ")); 215 | DEBUG_PRINT(data[4], HEX); DEBUG_PRINT(F(" =? ")); 216 | DEBUG_PRINTLN((data[0] + data[1] + data[2] + data[3]) & 0xFF, HEX); 217 | 218 | // Check we read 40 bits and that the checksum matches. 219 | if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) { 220 | _lastresult = true; 221 | return _lastresult; 222 | } 223 | else { 224 | DEBUG_PRINTLN(F("Checksum failure!")); 225 | _lastresult = false; 226 | return _lastresult; 227 | } 228 | } 229 | 230 | // Expect the signal line to be at the specified level for a period of time and 231 | // return a count of loop cycles spent at that level (this cycle count can be 232 | // used to compare the relative time of two pulses). If more than a millisecond 233 | // ellapses without the level changing then the call fails with a 0 response. 234 | // This is adapted from Arduino's pulseInLong function (which is only available 235 | // in the very latest IDE versions): 236 | // https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_pulse.c 237 | uint32_t DHT::expectPulse(bool level) { 238 | uint32_t count = 0; 239 | // On AVR platforms use direct GPIO port access as it's much faster and better 240 | // for catching pulses that are 10's of microseconds in length: 241 | #ifdef __AVR 242 | uint8_t portState = level ? _bit : 0; 243 | while ((*portInputRegister(_port) & _bit) == portState) { 244 | if (count++ >= _maxcycles) { 245 | return 0; // Exceeded timeout, fail. 246 | } 247 | } 248 | // Otherwise fall back to using digitalRead (this seems to be necessary on ESP8266 249 | // right now, perhaps bugs in direct port access functions?). 250 | #else 251 | while (digitalRead(_pin) == level) { 252 | if (count++ >= _maxcycles) { 253 | return 0; // Exceeded timeout, fail. 254 | } 255 | } 256 | #endif 257 | 258 | return count; 259 | } 260 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/DHT.h: -------------------------------------------------------------------------------- 1 | /* DHT library 2 | 3 | MIT license 4 | written by Adafruit Industries 5 | */ 6 | #ifndef DHT_H 7 | #define DHT_H 8 | 9 | #if ARDUINO >= 100 10 | #include "Arduino.h" 11 | #else 12 | #include "WProgram.h" 13 | #endif 14 | 15 | 16 | // Uncomment to enable printing out nice debug messages. 17 | //#define DHT_DEBUG 18 | 19 | // Define where debug output will be printed. 20 | #define DEBUG_PRINTER Serial 21 | 22 | // Setup debug printing macros. 23 | #ifdef DHT_DEBUG 24 | #define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); } 25 | #define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); } 26 | #else 27 | #define DEBUG_PRINT(...) {} 28 | #define DEBUG_PRINTLN(...) {} 29 | #endif 30 | 31 | // Define types of sensors. 32 | #define DHT11 11 33 | #define DHT22 22 34 | #define DHT21 21 35 | #define AM2301 21 36 | 37 | 38 | class DHT { 39 | public: 40 | DHT(uint8_t pin, uint8_t type, uint8_t count=6); 41 | void begin(void); 42 | float readTemperature(bool S=false, bool force=false); 43 | float convertCtoF(float); 44 | float convertFtoC(float); 45 | float computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit=true); 46 | float readHumidity(bool force=false); 47 | boolean read(bool force=false); 48 | 49 | private: 50 | uint8_t data[5]; 51 | uint8_t _pin, _type; 52 | #ifdef __AVR 53 | // Use direct GPIO access on an 8-bit AVR so keep track of the port and bitmask 54 | // for the digital pin connected to the DHT. Other platforms will use digitalRead. 55 | uint8_t _bit, _port; 56 | #endif 57 | uint32_t _lastreadtime, _maxcycles; 58 | bool _lastresult; 59 | 60 | uint32_t expectPulse(bool level); 61 | 62 | }; 63 | 64 | class InterruptLock { 65 | public: 66 | InterruptLock() { 67 | noInterrupts(); 68 | } 69 | ~InterruptLock() { 70 | interrupts(); 71 | } 72 | 73 | }; 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/DHT_U.cpp: -------------------------------------------------------------------------------- 1 | // DHT Temperature & Humidity Unified Sensor Library 2 | // Copyright (c) 2014 Adafruit Industries 3 | // Author: Tony DiCola 4 | 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | #include "DHT_U.h" 23 | 24 | DHT_Unified::DHT_Unified(uint8_t pin, uint8_t type, uint8_t count, int32_t tempSensorId, int32_t humiditySensorId): 25 | _dht(pin, type, count), 26 | _type(type), 27 | _temp(this, tempSensorId), 28 | _humidity(this, humiditySensorId) 29 | {} 30 | 31 | void DHT_Unified::begin() { 32 | _dht.begin(); 33 | } 34 | 35 | void DHT_Unified::setName(sensor_t* sensor) { 36 | switch(_type) { 37 | case DHT11: 38 | strncpy(sensor->name, "DHT11", sizeof(sensor->name) - 1); 39 | break; 40 | case DHT21: 41 | strncpy(sensor->name, "DHT21", sizeof(sensor->name) - 1); 42 | break; 43 | case DHT22: 44 | strncpy(sensor->name, "DHT22", sizeof(sensor->name) - 1); 45 | break; 46 | default: 47 | // TODO: Perhaps this should be an error? However main DHT library doesn't enforce 48 | // restrictions on the sensor type value. Pick a generic name for now. 49 | strncpy(sensor->name, "DHT?", sizeof(sensor->name) - 1); 50 | break; 51 | } 52 | sensor->name[sizeof(sensor->name)- 1] = 0; 53 | } 54 | 55 | void DHT_Unified::setMinDelay(sensor_t* sensor) { 56 | switch(_type) { 57 | case DHT11: 58 | sensor->min_delay = 1000000L; // 1 second (in microseconds) 59 | break; 60 | case DHT21: 61 | sensor->min_delay = 2000000L; // 2 seconds (in microseconds) 62 | break; 63 | case DHT22: 64 | sensor->min_delay = 2000000L; // 2 seconds (in microseconds) 65 | break; 66 | default: 67 | // Default to slowest sample rate in case of unknown type. 68 | sensor->min_delay = 2000000L; // 2 seconds (in microseconds) 69 | break; 70 | } 71 | } 72 | 73 | DHT_Unified::Temperature::Temperature(DHT_Unified* parent, int32_t id): 74 | _parent(parent), 75 | _id(id) 76 | {} 77 | 78 | bool DHT_Unified::Temperature::getEvent(sensors_event_t* event) { 79 | // Clear event definition. 80 | memset(event, 0, sizeof(sensors_event_t)); 81 | // Populate sensor reading values. 82 | event->version = sizeof(sensors_event_t); 83 | event->sensor_id = _id; 84 | event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; 85 | event->timestamp = millis(); 86 | event->temperature = _parent->_dht.readTemperature(); 87 | 88 | return true; 89 | } 90 | 91 | void DHT_Unified::Temperature::getSensor(sensor_t* sensor) { 92 | // Clear sensor definition. 93 | memset(sensor, 0, sizeof(sensor_t)); 94 | // Set sensor name. 95 | _parent->setName(sensor); 96 | // Set version and ID 97 | sensor->version = DHT_SENSOR_VERSION; 98 | sensor->sensor_id = _id; 99 | // Set type and characteristics. 100 | sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; 101 | _parent->setMinDelay(sensor); 102 | switch (_parent->_type) { 103 | case DHT11: 104 | sensor->max_value = 50.0F; 105 | sensor->min_value = 0.0F; 106 | sensor->resolution = 2.0F; 107 | break; 108 | case DHT21: 109 | sensor->max_value = 80.0F; 110 | sensor->min_value = -40.0F; 111 | sensor->resolution = 0.1F; 112 | break; 113 | case DHT22: 114 | sensor->max_value = 125.0F; 115 | sensor->min_value = -40.0F; 116 | sensor->resolution = 0.1F; 117 | break; 118 | default: 119 | // Unknown type, default to 0. 120 | sensor->max_value = 0.0F; 121 | sensor->min_value = 0.0F; 122 | sensor->resolution = 0.0F; 123 | break; 124 | } 125 | } 126 | 127 | DHT_Unified::Humidity::Humidity(DHT_Unified* parent, int32_t id): 128 | _parent(parent), 129 | _id(id) 130 | {} 131 | 132 | bool DHT_Unified::Humidity::getEvent(sensors_event_t* event) { 133 | // Clear event definition. 134 | memset(event, 0, sizeof(sensors_event_t)); 135 | // Populate sensor reading values. 136 | event->version = sizeof(sensors_event_t); 137 | event->sensor_id = _id; 138 | event->type = SENSOR_TYPE_RELATIVE_HUMIDITY; 139 | event->timestamp = millis(); 140 | event->relative_humidity = _parent->_dht.readHumidity(); 141 | 142 | return true; 143 | } 144 | 145 | void DHT_Unified::Humidity::getSensor(sensor_t* sensor) { 146 | // Clear sensor definition. 147 | memset(sensor, 0, sizeof(sensor_t)); 148 | // Set sensor name. 149 | _parent->setName(sensor); 150 | // Set version and ID 151 | sensor->version = DHT_SENSOR_VERSION; 152 | sensor->sensor_id = _id; 153 | // Set type and characteristics. 154 | sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY; 155 | _parent->setMinDelay(sensor); 156 | switch (_parent->_type) { 157 | case DHT11: 158 | sensor->max_value = 80.0F; 159 | sensor->min_value = 20.0F; 160 | sensor->resolution = 5.0F; 161 | break; 162 | case DHT21: 163 | sensor->max_value = 100.0F; 164 | sensor->min_value = 0.0F; 165 | sensor->resolution = 0.1F; 166 | break; 167 | case DHT22: 168 | sensor->max_value = 100.0F; 169 | sensor->min_value = 0.0F; 170 | sensor->resolution = 0.1F; 171 | break; 172 | default: 173 | // Unknown type, default to 0. 174 | sensor->max_value = 0.0F; 175 | sensor->min_value = 0.0F; 176 | sensor->resolution = 0.0F; 177 | break; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/DHT_U.h: -------------------------------------------------------------------------------- 1 | // DHT Temperature & Humidity Unified Sensor Library 2 | // Copyright (c) 2014 Adafruit Industries 3 | // Author: Tony DiCola 4 | 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | #ifndef DHT_U_H 23 | #define DHT_U_H 24 | 25 | #include 26 | #include 27 | 28 | #define DHT_SENSOR_VERSION 1 29 | 30 | class DHT_Unified { 31 | public: 32 | DHT_Unified(uint8_t pin, uint8_t type, uint8_t count=6, int32_t tempSensorId=-1, int32_t humiditySensorId=-1); 33 | void begin(); 34 | 35 | class Temperature : public Adafruit_Sensor { 36 | public: 37 | Temperature(DHT_Unified* parent, int32_t id); 38 | bool getEvent(sensors_event_t* event); 39 | void getSensor(sensor_t* sensor); 40 | 41 | private: 42 | DHT_Unified* _parent; 43 | int32_t _id; 44 | 45 | }; 46 | 47 | class Humidity : public Adafruit_Sensor { 48 | public: 49 | Humidity(DHT_Unified* parent, int32_t id); 50 | bool getEvent(sensors_event_t* event); 51 | void getSensor(sensor_t* sensor); 52 | 53 | private: 54 | DHT_Unified* _parent; 55 | int32_t _id; 56 | 57 | }; 58 | 59 | Temperature temperature() { 60 | return _temp; 61 | } 62 | 63 | Humidity humidity() { 64 | return _humidity; 65 | } 66 | 67 | private: 68 | DHT _dht; 69 | uint8_t _type; 70 | Temperature _temp; 71 | Humidity _humidity; 72 | 73 | void setName(sensor_t* sensor); 74 | void setMinDelay(sensor_t* sensor); 75 | 76 | }; 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/README.md: -------------------------------------------------------------------------------- 1 | This is an Arduino library for the DHT series of low cost temperature/humidity sensors. 2 | 3 | Tutorial: https://learn.adafruit.com/dht 4 | 5 | To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder DHT. Check that the DHT folder contains DHT.cpp and DHT.h. Place the DHT library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. 6 | 7 | # Adafruit DHT Humidity & Temperature Unified Sensor Library 8 | 9 | This library also includes an optional class for the 10 | [DHT humidity and temperature sensor](https://learn.adafruit.com/dht/overview) 11 | which is designed to work with the [Adafruit unified sensor library](https://learn.adafruit.com/using-the-adafruit-unified-sensor-driver/introduction). 12 | 13 | You must have the following Arduino libraries installed to use this class: 14 | 15 | - [Adafruit Unified Sensor Library](https://github.com/adafruit/Adafruit_Sensor) 16 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/examples/DHT_Unified_Sensor/DHT_Unified_Sensor.ino: -------------------------------------------------------------------------------- 1 | // DHT Temperature & Humidity Sensor 2 | // Unified Sensor Library Example 3 | // Written by Tony DiCola for Adafruit Industries 4 | // Released under an MIT license. 5 | 6 | // Depends on the following Arduino libraries: 7 | // - Adafruit Unified Sensor Library: https://github.com/adafruit/Adafruit_Sensor 8 | // - DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #define DHTPIN 2 // Pin which is connected to the DHT sensor. 15 | 16 | // Uncomment the type of sensor in use: 17 | //#define DHTTYPE DHT11 // DHT 11 18 | #define DHTTYPE DHT22 // DHT 22 (AM2302) 19 | //#define DHTTYPE DHT21 // DHT 21 (AM2301) 20 | 21 | // See guide for details on sensor wiring and usage: 22 | // https://learn.adafruit.com/dht/overview 23 | 24 | DHT_Unified dht(DHTPIN, DHTTYPE); 25 | 26 | uint32_t delayMS; 27 | 28 | void setup() { 29 | Serial.begin(9600); 30 | // Initialize device. 31 | dht.begin(); 32 | Serial.println("DHTxx Unified Sensor Example"); 33 | // Print temperature sensor details. 34 | sensor_t sensor; 35 | dht.temperature().getSensor(&sensor); 36 | Serial.println("------------------------------------"); 37 | Serial.println("Temperature"); 38 | Serial.print ("Sensor: "); Serial.println(sensor.name); 39 | Serial.print ("Driver Ver: "); Serial.println(sensor.version); 40 | Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); 41 | Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" *C"); 42 | Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" *C"); 43 | Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" *C"); 44 | Serial.println("------------------------------------"); 45 | // Print humidity sensor details. 46 | dht.humidity().getSensor(&sensor); 47 | Serial.println("------------------------------------"); 48 | Serial.println("Humidity"); 49 | Serial.print ("Sensor: "); Serial.println(sensor.name); 50 | Serial.print ("Driver Ver: "); Serial.println(sensor.version); 51 | Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); 52 | Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println("%"); 53 | Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println("%"); 54 | Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println("%"); 55 | Serial.println("------------------------------------"); 56 | // Set delay between sensor readings based on sensor details. 57 | delayMS = sensor.min_delay / 1000; 58 | } 59 | 60 | void loop() { 61 | // Delay between measurements. 62 | delay(delayMS); 63 | // Get temperature event and print its value. 64 | sensors_event_t event; 65 | dht.temperature().getEvent(&event); 66 | if (isnan(event.temperature)) { 67 | Serial.println("Error reading temperature!"); 68 | } 69 | else { 70 | Serial.print("Temperature: "); 71 | Serial.print(event.temperature); 72 | Serial.println(" *C"); 73 | } 74 | // Get humidity event and print its value. 75 | dht.humidity().getEvent(&event); 76 | if (isnan(event.relative_humidity)) { 77 | Serial.println("Error reading humidity!"); 78 | } 79 | else { 80 | Serial.print("Humidity: "); 81 | Serial.print(event.relative_humidity); 82 | Serial.println("%"); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/examples/DHTtester/DHTtester.ino: -------------------------------------------------------------------------------- 1 | // Example testing sketch for various DHT humidity/temperature sensors 2 | // Written by ladyada, public domain 3 | 4 | #include "DHT.h" 5 | 6 | #define DHTPIN 2 // what digital pin we're connected to 7 | 8 | // Uncomment whatever type you're using! 9 | //#define DHTTYPE DHT11 // DHT 11 10 | #define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 11 | //#define DHTTYPE DHT21 // DHT 21 (AM2301) 12 | 13 | // Connect pin 1 (on the left) of the sensor to +5V 14 | // NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1 15 | // to 3.3V instead of 5V! 16 | // Connect pin 2 of the sensor to whatever your DHTPIN is 17 | // Connect pin 4 (on the right) of the sensor to GROUND 18 | // Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor 19 | 20 | // Initialize DHT sensor. 21 | // Note that older versions of this library took an optional third parameter to 22 | // tweak the timings for faster processors. This parameter is no longer needed 23 | // as the current DHT reading algorithm adjusts itself to work on faster procs. 24 | DHT dht(DHTPIN, DHTTYPE); 25 | 26 | void setup() { 27 | Serial.begin(9600); 28 | Serial.println("DHTxx test!"); 29 | 30 | dht.begin(); 31 | } 32 | 33 | void loop() { 34 | // Wait a few seconds between measurements. 35 | delay(2000); 36 | 37 | // Reading temperature or humidity takes about 250 milliseconds! 38 | // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) 39 | float h = dht.readHumidity(); 40 | // Read temperature as Celsius (the default) 41 | float t = dht.readTemperature(); 42 | // Read temperature as Fahrenheit (isFahrenheit = true) 43 | float f = dht.readTemperature(true); 44 | 45 | // Check if any reads failed and exit early (to try again). 46 | if (isnan(h) || isnan(t) || isnan(f)) { 47 | Serial.println("Failed to read from DHT sensor!"); 48 | return; 49 | } 50 | 51 | // Compute heat index in Fahrenheit (the default) 52 | float hif = dht.computeHeatIndex(f, h); 53 | // Compute heat index in Celsius (isFahreheit = false) 54 | float hic = dht.computeHeatIndex(t, h, false); 55 | 56 | Serial.print("Humidity: "); 57 | Serial.print(h); 58 | Serial.print(" %\t"); 59 | Serial.print("Temperature: "); 60 | Serial.print(t); 61 | Serial.print(" *C "); 62 | Serial.print(f); 63 | Serial.print(" *F\t"); 64 | Serial.print("Heat index: "); 65 | Serial.print(hic); 66 | Serial.print(" *C "); 67 | Serial.print(hif); 68 | Serial.println(" *F"); 69 | } 70 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/keywords.txt: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Syntax Coloring Map For DHT-sensor-library 3 | ########################################### 4 | 5 | ########################################### 6 | # Datatypes (KEYWORD1) 7 | ########################################### 8 | 9 | DHT KEYWORD1 10 | 11 | ########################################### 12 | # Methods and Functions (KEYWORD2) 13 | ########################################### 14 | 15 | begin KEYWORD2 16 | readTemperature KEYWORD2 17 | convertCtoF KEYWORD2 18 | convertFtoC KEYWORD2 19 | computeHeatIndex KEYWORD2 20 | readHumidity KEYWORD2 21 | read KEYWORD2 22 | 23 | -------------------------------------------------------------------------------- /Arduino/libraries/DHT_sensor_library/library.properties: -------------------------------------------------------------------------------- 1 | name=DHT sensor library 2 | version=1.3.0 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=Arduino library for DHT11, DHT22, etc Temp & Humidity Sensors 6 | paragraph=Arduino library for DHT11, DHT22, etc Temp & Humidity Sensors 7 | category=Sensors 8 | url=https://github.com/adafruit/DHT-sensor-library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /Arduino/libraries/SHT1x/CHANGES.txt: -------------------------------------------------------------------------------- 1 | 2011-09-20 2 | * Conditionally include Arduino.h for compatibility with Arduino 1.0 3 | 4 | 2010-07-23 5 | * Added SHT7x to list of supported sensors. 6 | * Fixed temperature offset in humidity calculation. 7 | -------------------------------------------------------------------------------- /Arduino/libraries/SHT1x/DISTRIBUTION: -------------------------------------------------------------------------------- 1 | Copyright 2009 Jonathan Oxer / 2 | Copyright 2008 Maurice Ribble / 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | http://www.gnu.org/licenses/ 10 | -------------------------------------------------------------------------------- /Arduino/libraries/SHT1x/README.markdown: -------------------------------------------------------------------------------- 1 | SHT1x Temperature / Humidity Sensor Library for Arduino 2 | ======================================================= 3 | Copyright 2009 Jonathan Oxer jon@oxer.com.au / http://www.practicalarduino.com 4 | Copyright 2008 Maurice Ribble ribblem@yahoo.com / http://www.glacialwanderer.com 5 | 6 | Provides a simple interface to the SHT1x series (SHT10, SHT11, SHT15) 7 | and SHT7x series (SHT71, SHT75) temperature / humidity sensors from 8 | Sensirion, http://www.sensirion.com. These sensors use a "2-wire" 9 | communications buss that is similar to I2C and can co-exist on the same 10 | physical wire as I2C devices. 11 | 12 | Installation 13 | ------------ 14 | Download the directory "SHT1x" and move it into the "libraries" 15 | directory inside your sketchbook directory, then restart the Arduino 16 | IDE. You will then see it listed under File->Examples->SHT1x. 17 | 18 | Usage 19 | ----- 20 | The library is instantiated as an object with methods provided to read 21 | relative humidity and temperature. Include it in your sketch and then 22 | create an object, specifying the pins to use for communication with the 23 | sensor: 24 | 25 | #include 26 | #define dataPin 10 27 | #define clockPin 11 28 | SHT1x sht1x(dataPin, clockPin); 29 | 30 | You can then call methods on that object within your program. In this 31 | example we created an object called "sht1x", but it could have been 32 | called whatever you like. A complete example program is included with 33 | the library and can be accessed from the File->Examples->SHT1x menu. 34 | 35 | ### readTemperatureC() ### 36 | 37 | Returns a float within the valid range of the sensor of -40 to +123.8C. 38 | A value of -40 is returned in the event of a communication error with 39 | the sensor. 40 | 41 | Example: 42 | 43 | float tempC = sht1x.readTemperatureC(); 44 | 45 | ### readTemperatureF() ### 46 | 47 | Returns a float within the valid range of the sensor of -40 to +254.9F. 48 | A value of -40 is returned in the event of a communication error with 49 | the sensor. 50 | 51 | Example: 52 | 53 | float tempF = sht1x.readTemperatureF(); 54 | 55 | ### readHumidity() ### 56 | 57 | Returns a float within the valid range of the sensor of 0 to 100%. 58 | A negative value is returned in the event of a communication error with 59 | the sensor. 60 | 61 | Example: 62 | 63 | float humidity = sht1x.readHumidity(); 64 | -------------------------------------------------------------------------------- /Arduino/libraries/SHT1x/SHT1x.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SHT1x Library 3 | * 4 | * Copyright 2009 Jonathan Oxer / 5 | * Based on previous work by: 6 | * Maurice Ribble: 7 | * Wayne ?: 8 | * 9 | * Manages communication with SHT1x series (SHT10, SHT11, SHT15) 10 | * temperature / humidity sensors from Sensirion (www.sensirion.com). 11 | */ 12 | #if (ARDUINO >= 100) 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | #include "SHT1x.h" 19 | 20 | SHT1x::SHT1x(int dataPin, int clockPin) 21 | { 22 | _dataPin = dataPin; 23 | _clockPin = clockPin; 24 | } 25 | 26 | 27 | /* ================ Public methods ================ */ 28 | 29 | /** 30 | * Reads the current temperature in degrees Celsius 31 | */ 32 | float SHT1x::readTemperatureC() 33 | { 34 | int _val; // Raw value returned from sensor 35 | float _temperature; // Temperature derived from raw value 36 | 37 | // Conversion coefficients from SHT15 datasheet 38 | const float D1 = -40.0; // for 14 Bit @ 5V 39 | const float D2 = 0.01; // for 14 Bit DEGC 40 | 41 | // Fetch raw value 42 | _val = readTemperatureRaw(); 43 | 44 | // Convert raw value to degrees Celsius 45 | _temperature = (_val * D2) + D1; 46 | 47 | return (_temperature); 48 | } 49 | 50 | /** 51 | * Reads the current temperature in degrees Fahrenheit 52 | */ 53 | float SHT1x::readTemperatureF() 54 | { 55 | int _val; // Raw value returned from sensor 56 | float _temperature; // Temperature derived from raw value 57 | 58 | // Conversion coefficients from SHT15 datasheet 59 | const float D1 = -40.0; // for 14 Bit @ 5V 60 | const float D2 = 0.018; // for 14 Bit DEGF 61 | 62 | // Fetch raw value 63 | _val = readTemperatureRaw(); 64 | 65 | // Convert raw value to degrees Fahrenheit 66 | _temperature = (_val * D2) + D1; 67 | 68 | return (_temperature); 69 | } 70 | 71 | /** 72 | * Reads current temperature-corrected relative humidity 73 | */ 74 | float SHT1x::readHumidity() 75 | { 76 | int _val; // Raw humidity value returned from sensor 77 | float _linearHumidity; // Humidity with linear correction applied 78 | float _correctedHumidity; // Temperature-corrected humidity 79 | float _temperature; // Raw temperature value 80 | 81 | // Conversion coefficients from SHT15 datasheet 82 | const float C1 = -4.0; // for 12 Bit 83 | const float C2 = 0.0405; // for 12 Bit 84 | const float C3 = -0.0000028; // for 12 Bit 85 | const float T1 = 0.01; // for 14 Bit @ 5V 86 | const float T2 = 0.00008; // for 14 Bit @ 5V 87 | 88 | // Command to send to the SHT1x to request humidity 89 | int _gHumidCmd = 0b00000101; 90 | 91 | // Fetch the value from the sensor 92 | sendCommandSHT(_gHumidCmd, _dataPin, _clockPin); 93 | waitForResultSHT(_dataPin); 94 | _val = getData16SHT(_dataPin, _clockPin); 95 | skipCrcSHT(_dataPin, _clockPin); 96 | 97 | // Apply linear conversion to raw value 98 | _linearHumidity = C1 + C2 * _val + C3 * _val * _val; 99 | 100 | // Get current temperature for humidity correction 101 | _temperature = readTemperatureC(); 102 | 103 | // Correct humidity value for current temperature 104 | _correctedHumidity = (_temperature - 25.0 ) * (T1 + T2 * _val) + _linearHumidity; 105 | 106 | return (_correctedHumidity); 107 | } 108 | 109 | 110 | /* ================ Private methods ================ */ 111 | 112 | /** 113 | * Reads the current raw temperature value 114 | */ 115 | float SHT1x::readTemperatureRaw() 116 | { 117 | int _val; 118 | 119 | // Command to send to the SHT1x to request Temperature 120 | int _gTempCmd = 0b00000011; 121 | 122 | sendCommandSHT(_gTempCmd, _dataPin, _clockPin); 123 | waitForResultSHT(_dataPin); 124 | _val = getData16SHT(_dataPin, _clockPin); 125 | skipCrcSHT(_dataPin, _clockPin); 126 | 127 | return (_val); 128 | } 129 | 130 | /** 131 | */ 132 | int SHT1x::shiftIn(int _dataPin, int _clockPin, int _numBits) 133 | { 134 | int ret = 0; 135 | int i; 136 | 137 | for (i=0; i<_numBits; ++i) 138 | { 139 | digitalWrite(_clockPin, HIGH); 140 | delay(10); // I don't know why I need this, but without it I don't get my 8 lsb of temp 141 | ret = ret*2 + digitalRead(_dataPin); 142 | digitalWrite(_clockPin, LOW); 143 | } 144 | 145 | return(ret); 146 | } 147 | 148 | /** 149 | */ 150 | void SHT1x::sendCommandSHT(int _command, int _dataPin, int _clockPin) 151 | { 152 | int ack; 153 | 154 | // Transmission Start 155 | pinMode(_dataPin, OUTPUT); 156 | pinMode(_clockPin, OUTPUT); 157 | digitalWrite(_dataPin, HIGH); 158 | digitalWrite(_clockPin, HIGH); 159 | digitalWrite(_dataPin, LOW); 160 | digitalWrite(_clockPin, LOW); 161 | digitalWrite(_clockPin, HIGH); 162 | digitalWrite(_dataPin, HIGH); 163 | digitalWrite(_clockPin, LOW); 164 | 165 | // The command (3 msb are address and must be 000, and last 5 bits are command) 166 | shiftOut(_dataPin, _clockPin, MSBFIRST, _command); 167 | 168 | // Verify we get the correct ack 169 | digitalWrite(_clockPin, HIGH); 170 | pinMode(_dataPin, INPUT); 171 | ack = digitalRead(_dataPin); 172 | if (ack != LOW) { 173 | //Serial.println("Ack Error 0"); 174 | } 175 | digitalWrite(_clockPin, LOW); 176 | ack = digitalRead(_dataPin); 177 | if (ack != HIGH) { 178 | //Serial.println("Ack Error 1"); 179 | } 180 | } 181 | 182 | /** 183 | */ 184 | void SHT1x::waitForResultSHT(int _dataPin) 185 | { 186 | int i; 187 | int ack; 188 | 189 | pinMode(_dataPin, INPUT); 190 | 191 | for(i= 0; i < 100; ++i) 192 | { 193 | delay(10); 194 | ack = digitalRead(_dataPin); 195 | 196 | if (ack == LOW) { 197 | break; 198 | } 199 | } 200 | 201 | if (ack == HIGH) { 202 | //Serial.println("Ack Error 2"); // Can't do serial stuff here, need another way of reporting errors 203 | } 204 | } 205 | 206 | /** 207 | */ 208 | int SHT1x::getData16SHT(int _dataPin, int _clockPin) 209 | { 210 | int val; 211 | 212 | // Get the most significant bits 213 | pinMode(_dataPin, INPUT); 214 | pinMode(_clockPin, OUTPUT); 215 | val = shiftIn(_dataPin, _clockPin, 8); 216 | val *= 256; 217 | 218 | // Send the required ack 219 | pinMode(_dataPin, OUTPUT); 220 | digitalWrite(_dataPin, HIGH); 221 | digitalWrite(_dataPin, LOW); 222 | digitalWrite(_clockPin, HIGH); 223 | digitalWrite(_clockPin, LOW); 224 | 225 | // Get the least significant bits 226 | pinMode(_dataPin, INPUT); 227 | val |= shiftIn(_dataPin, _clockPin, 8); 228 | 229 | return val; 230 | } 231 | 232 | /** 233 | */ 234 | void SHT1x::skipCrcSHT(int _dataPin, int _clockPin) 235 | { 236 | // Skip acknowledge to end trans (no CRC) 237 | pinMode(_dataPin, OUTPUT); 238 | pinMode(_clockPin, OUTPUT); 239 | 240 | digitalWrite(_dataPin, HIGH); 241 | digitalWrite(_clockPin, HIGH); 242 | digitalWrite(_clockPin, LOW); 243 | } 244 | -------------------------------------------------------------------------------- /Arduino/libraries/SHT1x/SHT1x.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SHT1x Library 3 | * 4 | * Copyright 2009 Jonathan Oxer / 5 | * Based on previous work by: 6 | * Maurice Ribble: 7 | * Wayne ?: 8 | * 9 | * Manages communication with SHT1x series (SHT10, SHT11, SHT15) 10 | * temperature / humidity sensors from Sensirion (www.sensirion.com). 11 | */ 12 | #ifndef SHT1x_h 13 | #define SHT1x_h 14 | 15 | #if (ARDUINO >= 100) 16 | #include 17 | #else 18 | #include 19 | #endif 20 | 21 | class SHT1x 22 | { 23 | public: 24 | SHT1x(int dataPin, int clockPin); 25 | float readHumidity(); 26 | float readTemperatureC(); 27 | float readTemperatureF(); 28 | private: 29 | int _dataPin; 30 | int _clockPin; 31 | int _numBits; 32 | float readTemperatureRaw(); 33 | int shiftIn(int _dataPin, int _clockPin, int _numBits); 34 | void sendCommandSHT(int _command, int _dataPin, int _clockPin); 35 | void waitForResultSHT(int _dataPin); 36 | int getData16SHT(int _dataPin, int _clockPin); 37 | void skipCrcSHT(int _dataPin, int _clockPin); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /Arduino/libraries/SHT1x/examples/ReadSHT1xValues/ReadSHT1xValues.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ReadSHT1xValues 3 | * 4 | * Read temperature and humidity values from an SHT1x-series (SHT10, 5 | * SHT11, SHT15) sensor. 6 | * 7 | * Copyright 2009 Jonathan Oxer 8 | * www.practicalarduino.com 9 | */ 10 | 11 | #include 12 | 13 | // Specify data and clock connections and instantiate SHT1x object 14 | #define dataPin 10 15 | #define clockPin 11 16 | SHT1x sht1x(dataPin, clockPin); 17 | 18 | void setup() 19 | { 20 | Serial.begin(38400); // Open serial connection to report values to host 21 | Serial.println("Starting up"); 22 | } 23 | 24 | void loop() 25 | { 26 | float temp_c; 27 | float temp_f; 28 | float humidity; 29 | 30 | // Read values from the sensor 31 | temp_c = sht1x.readTemperatureC(); 32 | temp_f = sht1x.readTemperatureF(); 33 | humidity = sht1x.readHumidity(); 34 | 35 | // Print the values to the serial port 36 | Serial.print("Temperature: "); 37 | Serial.print(temp_c, DEC); 38 | Serial.print("C / "); 39 | Serial.print(temp_f, DEC); 40 | Serial.print("F. Humidity: "); 41 | Serial.print(humidity); 42 | Serial.println("%"); 43 | 44 | delay(2000); 45 | } 46 | -------------------------------------------------------------------------------- /Arduino/libraries/SHT1x/keywords.txt: -------------------------------------------------------------------------------- 1 | SHT1x KEYWORD1 2 | readHumidity KEYWORD2 3 | readTemperatureC KEYWORD2 4 | readTemperatureF KEYWORD2 5 | -------------------------------------------------------------------------------- /Design/PowerConvert.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/PowerConvert.fzz -------------------------------------------------------------------------------- /Design/PowerConvert_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/PowerConvert_schem.png -------------------------------------------------------------------------------- /Design/Solinst-20170409.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst-20170409.fzz -------------------------------------------------------------------------------- /Design/Solinst.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst.fzz -------------------------------------------------------------------------------- /Design/Solinst_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst_bb.png -------------------------------------------------------------------------------- /Design/Solinst_bb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst_bb2.png -------------------------------------------------------------------------------- /Design/Solinst_label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst_label.png -------------------------------------------------------------------------------- /Design/Solinst_label.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst_label.psd -------------------------------------------------------------------------------- /Design/Solinst_label2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst_label2.png -------------------------------------------------------------------------------- /Design/Solinst_label2.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst_label2.psd -------------------------------------------------------------------------------- /Design/Solinst_label3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Design/Solinst_label3.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # solinst-array 2 | This is a personal project to read data from sensors 3 | 4 | See the Design folder for instructions to connect hardware 5 | 6 | ## Preparing the Raspberry Pi 7 | 8 | These instructions are based on a clean, updated install of Raspbian Linux 9 | 10 | - Install the following packages 11 | - exim4-base 12 | - ppp 13 | - screen 14 | - Run raspi-config 15 | - Configure localization 16 | - keyboard: Generic 104PC, English US 17 | - Timezone: America/Toronto 18 | - Enable sshd 19 | - Enable serial console 20 | - Edit /boot/cmdline.txt 21 | - remove "console=serial0,115200" from line 22 | - Reboot Raspberry Pi 23 | 24 | ## Software install 25 | 26 | Follow the README.md instructions from the Solinst-Array and pi-comm directories. 27 | 28 | **pi-comm** : Files needed to get the GSM modem to create ppp links for data exchange 29 | **Solinst-Array** : Scripts to run and manage the data collection and transmission 30 | 31 | ## Arduino 32 | 33 | Two Arduino programs to test the connections, and the communications program to help the Pi interact with the sensors 34 | - Solinst-Array : Software to help the Raspberry Pi interact with the connected instruments 35 | - Solinst-TestData : Send fake, formatted data to test communications from the Raspberry Pi 36 | - RainCounter : Test the operation and data readings from the rain collection instrument. 37 | 38 | ## Communicating with Sparkfun Data collection 39 | 40 | http://data.sparkfun.com/input/[publicKey]?private_key=[privateKey]&collect_date=[value]&dht_humid=[value]&dht_temp=[value]&rain_rate=[value]&soil_humid=[value]&soil_temp=[value]&sol_depth=[value]&sol_temp=[value] 41 | -------------------------------------------------------------------------------- /Solinst-Array/.gitignore: -------------------------------------------------------------------------------- 1 | /data/ 2 | -------------------------------------------------------------------------------- /Solinst-Array/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Solinst-Array 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /Solinst-Array/.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | Default 4 | 5 | /${PROJECT_DIR_NAME} 6 | 7 | python 2.7 8 | 9 | -------------------------------------------------------------------------------- /Solinst-Array/APIProject-1d4ee6021f22.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "service_account", 3 | "project_id": "in-works.net:api-project-961034775297", 4 | "private_key_id": "1d4ee6021f22f4e72181f1d59338acfe7da2c7d1", 5 | "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCg6SV6CdPF1zH8\n+6DqHs9TMvlcoU38NnJiXMZO/l7Hw0Vq2Jplm55j+ngBLtCjgi+XfC3OUBJusuPQ\nrB4x/aDCwzvREFKg/5SZVCYaAVvAtTqvFbh485seK3wnclCjS3lFGHHhB3b+1C3d\nTEDEWAXqdj+FMthM7id3EalI6LPqK6rYzVtdj1cRYskzgSmWng6ogXbfB+KBl9/U\n/4sQBsRIx4phBrh2sQXUntrvzqfslZ9TXS3Ml6v+0PqzHHwJHIKJankw6NTqB3Ch\nREmgZEeomeKj4Uaf/SyjTo5Uee7rWarEk6Jgk2TMsLpYIPPLCj/LYOO0UhA6vgTw\nuBDbzqz3AgMBAAECggEAIKnjNSg8iGscFx4fNpdFf76XtvF5iqqkwonRqaRiKgve\nEgfhI6IY33OvG5JcwOxC6+3FwJ0peLYwn6HoyT4SfaazBEfbdhobmJpn15yR+wbu\n4C65EThmMxQhskI200cVWWzSZRsmUSlSHBuIBDNYFBWn5EqDdO5dLYL0ybuPFggv\nlAC5IOQwDIg1Kju1obCuXZ+Sh9p91g841KtPlVr/a5NcOcd9YDUcsTtID/rKwpsD\nf7qdrO8qbtJcd2m7QEa7cu6lzC6pQYZfMbE5OBECjrsNpQrTPYeRvNOgxiAB2aE4\nL52R485tZKOau/aC2p+zv0g+G87LGK/3qBWjJwZPqQKBgQDbKL/jBULtWfdlJqWf\ngfSsUhK1TVRQEV07zh/nzB8n8ksn16JGbj9q+SZp2jnJ0HWi8e2mSsm3u0QqD7ic\nNcI2iJ1fAEowu6Ijaavi4FfMqnvSLtTkFn9k3hTcfv1v0tCQ6ioe6knx7RQLGrqE\nPm4A3omXoJdVgrrwzwb1omWRnwKBgQC79b7DcsfM8t2w1z09LYIPU6wl7FELPs1a\nFmZm0dIZ7R147F1ovBtXGIxml4D5rXF39HDW9e4Gd9FzDdHV6k9czJVSZvQImPiO\nDi+Tly6E3owM5TnycH+OIT0W0Q4UjdSMBAoinTgY5rtmHWxO8uyxoiFJ8KuikbKn\nwPOJ1wCVqQKBgG/D0kfmUQFWVjJBiUlVLwAKQvwu2YaTtGZhcif2ExV+HRHOiDU+\n2Bynvw1QexQOuU9F7ZpWnZSTbem9ZrpTOB4zgX4HWc6Mgd1pcH0dR+laMBc6Rtuj\nFYjNMPpZ0MmMS0z7/ksR1HAKJaScFu6GH/dVhfnLriGvr8JK8hOmpAGlAoGBAI0E\n+VUGfuVDqhSNyIJn7Fa3fkcNoFiBi+x1NesarTmKbzxUiliUGSclYeFu9fNdr+5B\n1Y9SAH2V0+0whyipnVWQoM+sMpdovcNG3WcsXFiP6B+cs/czdGAcjArcWmYNa1SJ\ni1kg//+ezSb2GFa7Z952N+eTzBIyogm+eHoId4XRAoGBANcEIsmzUXaHgcL7fBjy\nrL4wHdeHDtpyfJTBJrOC4gaOmDNpKGnwoscZOqruJ0ZPXxVQ99V8p88yIfLFUb6C\n/ilvpGL34iPSW03fYvHcE9XqqVuJhzbTv9iKo1E9OqL7L+FyzeqR+HvCP7sKGio5\nEvTa7V8qG7SONWPvD/kUOqtW\n-----END PRIVATE KEY-----\n", 6 | "client_email": "solinst@api-project-961034775297.in-works.net.iam.gserviceaccount.com", 7 | "client_id": "115673119907010001392", 8 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 9 | "token_uri": "https://accounts.google.com/o/oauth2/token", 10 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", 11 | "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/solinst%40api-project-961034775297.in-works.net.iam.gserviceaccount.com" 12 | } 13 | -------------------------------------------------------------------------------- /Solinst-Array/README.md: -------------------------------------------------------------------------------- 1 | # Management Scripts 2 | 3 | ## Copy/Move the following files 4 | **Destination:** /usr/local/solinst 5 | - modem-comm.sh 6 | - serial_read.py 7 | - web_submit.py 8 | - solinst.ini 9 | 10 | **Destination:** /etc/cron.d 11 | - solinst-cron 12 | 13 | **Destination:** /etc/init.d 14 | - modem-init to modem 15 | 16 | ## Adjust the following 17 | - Create directory: /usr/local/solinst/data 18 | - Make sure /usr/local/solinst/modem-comm.sh has execute permissions (0755) 19 | - Make sure /etc/cron.d/solinst-cron is owned by root 20 | - Add /etc/init.d/modem to initialization scripts 21 | - update-rc.d modem defaults 22 | - Edit /usr/local/solinst/solinst.ini 23 | - Correct serial port (/dev/ttyS0) 24 | - Correct public and private keys for data.sparkfun.com 25 | -------------------------------------------------------------------------------- /Solinst-Array/modem-comm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Do stuff here 4 | 5 | function toggle_modem { 6 | gpio export 18 out 7 | 8 | gpio -g write 18 0 9 | sleep 8 10 | gpio -g write 18 1 11 | } 12 | 13 | if [ ! -c /dev/ttyUSB2 ] 14 | then 15 | toggle_modem 16 | fi 17 | 18 | if [ -c /dev/ttyUSB2 ] 19 | then 20 | /usr/bin/pon fona 21 | 22 | sleep 10 23 | /usr/bin/python /usr/local/solinst/web_submit.py 24 | 25 | /usr/bin/poff fona 26 | 27 | # toggle_modem 28 | fi 29 | -------------------------------------------------------------------------------- /Solinst-Array/modem-init: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: modem 4 | # Required-Start: $remote_fs 5 | # Required-Stop: 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Initialize GSM modem and initially set time 9 | # Description: 10 | # 11 | # 12 | ### END INIT INFO 13 | 14 | # 15 | # Author: Curtis Ireland 16 | # 17 | 18 | # PATH should only include /usr/* if it runs after the mountnfs.sh script 19 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 20 | DESC="initialize modem" 21 | NAME=modem 22 | DAEMON=/usr/sbin/pppd 23 | 24 | # SCRIPTNAME=/etc/init.d/$NAME 25 | 26 | # Exit if the package is not installed 27 | [ -x "$DAEMON" ] || exit 0 28 | 29 | # Read configuration variable file if it is present 30 | #[ -r /etc/default/$NAME ] && . /etc/default/$NAME 31 | 32 | # Define LSB log_* functions. 33 | . /lib/lsb/init-functions 34 | 35 | toggle_modem() { 36 | gpio export 18 out 37 | 38 | gpio -g write 18 0 39 | sleep 8 40 | gpio -g write 18 1 41 | } 42 | 43 | adjust_time() { 44 | /usr/bin/pon fona 45 | 46 | sleep 5 47 | /usr/sbin/ntpdate pool.ntp.org 48 | /usr/bin/poff fona 49 | } 50 | 51 | case "$1" in 52 | start) 53 | echo "Starting GSM modem" 54 | if [ ! -c /dev/ttyUSB2 ] 55 | then 56 | toggle_modem 57 | fi 58 | 59 | if [ -c /dev/ttyUSB2 ] 60 | then 61 | adjust_time 62 | fi 63 | ;; 64 | stop) 65 | echo "Stopping GSM modem" 66 | if [ -c /dev/ttyUSB2 ] 67 | then 68 | toggle_modem 69 | fi 70 | 71 | ;; 72 | restart) 73 | $0 stop 74 | sleep 10 75 | $0 start 76 | ;; 77 | status) 78 | exit 0 79 | ;; 80 | *) 81 | echo "Usage: $SCRIPTNAME {start|stop|restart|status}" >&2 82 | exit 3 83 | ;; 84 | esac 85 | 86 | : 87 | -------------------------------------------------------------------------------- /Solinst-Array/serial_read.py: -------------------------------------------------------------------------------- 1 | import serial 2 | import time 3 | import storage.database as lite 4 | import datetime 5 | import os 6 | import ConfigParser 7 | 8 | # Load configuration 9 | config_file = "/usr/local/solinst/solinst.ini" 10 | if(not os.path.exists(config_file)): 11 | print("ERROR: Cannot find configuration file.") 12 | exit(-1) 13 | 14 | Config = ConfigParser.ConfigParser() 15 | Config.read(config_file) 16 | 17 | DEBUG = Config.getboolean("general", "debug") 18 | datadir = Config.get("general", "data_dir") 19 | serial_port = Config.get("serial_read", "serial_port") 20 | serial_baud = Config.getint("serial_read", "serial_baud") 21 | 22 | # Pre-declare variables 23 | vals = [] 24 | 25 | # port='/dev/ttyAMA0',\ 26 | ser = serial.Serial( 27 | port=serial_port,\ 28 | baudrate=serial_baud,\ 29 | parity=serial.PARITY_NONE,\ 30 | stopbits=serial.STOPBITS_ONE,\ 31 | bytesize=serial.EIGHTBITS,\ 32 | timeout=0) 33 | 34 | if DEBUG: print("connected to: " + ser.portstr) 35 | 36 | # Get the serial number of this raspberry pi 37 | ##serial = get_serial(); 38 | #serial = "pc-test" 39 | 40 | 41 | time.sleep(2) 42 | ser.write("\n") 43 | 44 | if DEBUG: print("Sent to serial - waiting for data") 45 | time.sleep(12) 46 | 47 | line = ser.readline().strip() 48 | vals = line.split(',') 49 | 50 | if DEBUG: print("Got data from serial:" + line) 51 | ser.close() 52 | 53 | 54 | # Store data into local database file 55 | # Determine the name of the database 56 | today = datetime.datetime.today() 57 | dbdate = today.strftime('%Y%m%d') 58 | db_filename = "sensordata-" + dbdate + ".sqlite" 59 | 60 | if DEBUG: print("Saving to database:" + db_filename) 61 | sensordb = lite.Database(datadir + db_filename) 62 | sensordb.addLine(vals) 63 | 64 | sensordb.close() 65 | -------------------------------------------------------------------------------- /Solinst-Array/solinst-cron: -------------------------------------------------------------------------------- 1 | # Cron schedule to manage data collection and transmission 2 | # 3 | # Collect data from attached sensor 4 | */5 * * * * root /usr/bin/python /usr/local/solinst/serial_read.py 5 | # 6 | #Transmit data to collection service 7 | 7,37 * * * * root /usr/local/solinst/modem-comm.sh 8 | -------------------------------------------------------------------------------- /Solinst-Array/solinst.ini: -------------------------------------------------------------------------------- 1 | [general] 2 | array_id=SA1701 3 | debug=False 4 | data_dir=data/ 5 | 6 | [serial_read] 7 | serial_port=/dev/ttyS0 8 | serial_baud=9600 9 | 10 | [web_submit] 11 | auth_file=APIProject-1d4ee6021f22.json 12 | data_file=solinst_data -------------------------------------------------------------------------------- /Solinst-Array/storage/.gitignore: -------------------------------------------------------------------------------- 1 | /__init__.pyc 2 | /database.pyc 3 | -------------------------------------------------------------------------------- /Solinst-Array/storage/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CurtisIreland/solinst-array/3ec30c97a0a4358b3c7008b4ce15ce5cfaf5291b/Solinst-Array/storage/__init__.py -------------------------------------------------------------------------------- /Solinst-Array/storage/database.py: -------------------------------------------------------------------------------- 1 | # Class to manage database storage 2 | 3 | import sqlite3 as lite 4 | # import datetime 5 | # import sys 6 | import os 7 | 8 | 9 | class Database: 10 | def __init__(self, dbfile): 11 | self.dbfile = dbfile 12 | 13 | self.connect() 14 | 15 | def connect(self): 16 | fileInit = True 17 | if (os.path.exists(self.dbfile)): 18 | fileInit = False 19 | 20 | self.con = lite.connect(self.dbfile) 21 | 22 | if(fileInit): 23 | self.initTable() 24 | 25 | def addLine(self, data): 26 | # sanity check on the data 27 | if(len(data) != 7): 28 | return -1 29 | 30 | query="INSERT INTO sensor_data( dht_temp, dht_humid, soil_temp, soil_humid, sol_temp, sol_depth, rain_rate) VALUES(?, ?, ?, ?, ?, ?, ?)" 31 | cur = self.con.cursor() 32 | 33 | # print data 34 | 35 | try: 36 | cur.execute(query, (data[0], data[1], data[2], data[3], data[4], data[5], data[6])) 37 | self.con.commit() 38 | except lite.Error, e: 39 | if self.con: 40 | self.con.rollback() 41 | print "Error %s:" % e.args[0] 42 | return(-1) 43 | 44 | return(0) 45 | 46 | def getUnsent(self): 47 | query = "SELECT * FROM sensor_data WHERE transmit='FALSE'" 48 | cur = self.con.cursor() 49 | 50 | try: 51 | cur.execute(query) 52 | self.con.commit() 53 | except lite.Error, e: 54 | if self.con: 55 | self.con.rollback() 56 | print "Error %s:" % e.args[0] 57 | return(-1) 58 | 59 | rows = cur.fetchall() 60 | return(rows) 61 | 62 | def sentData(self, raw_date): 63 | # collect_date = raw_date.strftime("%Y-%m-%d %H:%M:%S") 64 | collect_date = raw_date 65 | query = "UPDATE sensor_data SET transmit='TRUE' WHERE collect_date=?" 66 | cur = self.con.cursor() 67 | 68 | try: 69 | cur.execute(query, (collect_date,)) 70 | self.con.commit() 71 | except lite.Error, e: 72 | if self.con: 73 | self.con.rollback() 74 | print "Error %s:" % e.args[0] 75 | return(-1) 76 | 77 | return(0) 78 | 79 | def initTable(self): 80 | query = 'DROP TABLE IF EXISTS sensor_data; CREATE TABLE sensor_data ("collect_date" DATETIME PRIMARY KEY NOT NULL DEFAULT (CURRENT_TIMESTAMP) , "dht_temp" REAL NOT NULL , "dht_humid" REAL NOT NULL , "soil_temp" REAL NOT NULL , "soil_humid" REAL NOT NULL , "sol_temp" REAL NOT NULL , "sol_depth" REAL NOT NULL , "rain_rate" REAL NOT NULL , "transmit" BOOL NOT NULL DEFAULT FALSE)' 81 | cur = self.con.cursor() 82 | 83 | try: 84 | cur.executescript(query) 85 | self.con.commit() 86 | except lite.Error, e: 87 | if self.con: 88 | self.con.rollback() 89 | 90 | print "Error %s:" % e.args[0] 91 | return(-1) 92 | 93 | return(0) 94 | 95 | def close(self): 96 | self.con.close() 97 | -------------------------------------------------------------------------------- /Solinst-Array/web_submit.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import datetime 4 | import json 5 | import storage.database as lite 6 | import ConfigParser 7 | 8 | import gspread 9 | from oauth2client.service_account import ServiceAccountCredentials 10 | 11 | def file_list(datadir): 12 | filelist = [] 13 | for files in os.listdir(datadir): 14 | matches = re.search("sensordata-[0-9]+\.sqlite", files) 15 | if (matches): 16 | filelist.append(files) 17 | 18 | return(filelist) 19 | 20 | def login_open_sheet(oauth_key_file, spreadsheet): 21 | """Connect to Google Docs spreadsheet and return the first worksheet.""" 22 | try: 23 | scope = ['https://spreadsheets.google.com/feeds'] 24 | credentials = ServiceAccountCredentials.from_json_keyfile_name(oauth_key_file, scope) 25 | gc = gspread.authorize(credentials) 26 | worksheet = gc.open(spreadsheet).sheet1 27 | return worksheet 28 | except Exception as ex: 29 | print('Unable to login and get spreadsheet. Check OAuth credentials, spreadsheet name, and make sure spreadsheet is shared to the client_email address in the OAuth .json file!') 30 | print('Google sheet login failed with error:', ex) 31 | sys.exit(1) 32 | 33 | 34 | # if DEBUG: print("Rename old database file: " + newfile) 35 | 36 | #Load config file 37 | config_file = "/usr/local/solinst/solinst.ini" 38 | if(not os.path.exists(config_file)): 39 | print("ERROR: Cannot find configuration file.") 40 | exit(-1) 41 | 42 | Config = ConfigParser.ConfigParser() 43 | Config.read(config_file) 44 | 45 | DEBUG = Config.getboolean("general", "debug") 46 | datadir = Config.get("general", "data_dir") 47 | array_id = Config.get("general", "array_id") 48 | GDOCS_OAUTH_JSON = Config.get("web_submit", "auth_file") 49 | GDOCS_SPREADSHEET_NAME = Config.get("web_submit", "data_file") 50 | 51 | # Determine the name of the current database 52 | today = datetime.datetime.today() 53 | dbdate = today.strftime('%Y%m%d') 54 | db_filename = "sensordata-" + dbdate + ".sqlite" 55 | 56 | if DEBUG: print("Today's database file: " + db_filename) 57 | 58 | # Get list of database files 59 | filelist = file_list(datadir) 60 | for files in filelist: 61 | sensordb = lite.Database(datadir + files) 62 | 63 | datalist = sensordb.getUnsent() 64 | if(len(datalist) == 0): 65 | sensordb.close() 66 | # Rename file 67 | if(files != db_filename): 68 | newfile = files[:-7] + "_done" + files[-7:] 69 | os.rename(datadir + files, datadir + newfile) 70 | if DEBUG: print("Rename old database file: " + newfile) 71 | continue 72 | 73 | for data in datalist: 74 | if DEBUG: print('Logging sensor measurements to {0}'.format(GDOCS_SPREADSHEET_NAME)) 75 | 76 | worksheet = login_open_sheet(GDOCS_OAUTH_JSON, GDOCS_SPREADSHEET_NAME) 77 | worksheet.append_row((array_id, str(data[0]), str(data[1]), str(data[2]), str(data[3]), str(data[4]), str(data[5]), str(data[6]), str(data[7]), datetime.datetime.now())) 78 | 79 | sensordb.sentData(str(data[0])) 80 | if DEBUG: print("Sent data: " + str(data[0])) 81 | sensordb.close() 82 | if DEBUG: print("Close database: " + files) 83 | -------------------------------------------------------------------------------- /pi-comm/README.md: -------------------------------------------------------------------------------- 1 | # Communication Scripts 2 | 3 | This directory contains helper files in order to make communications work between the Raspberry Pi and the GPRS modem. 4 | 5 | * /etc/ppp/peers/fona 6 | * /etc/chatscripts/gprs 7 | 8 | Note: You will need to change your APN value on line 5 of the fona file to match your provider's 9 | 10 | Here are a few that I know of. 11 | 12 | Canada 13 | * Telus: sp.telus.com 14 | * Rogers: rogers-core-appl1.apn 15 | * Bell: pda.bell.ca (untested) 16 | 17 | United States 18 | * Verizon: vzwinternet (untested) 19 | * T-Mobile: fast.t-mobile.com 20 | 21 | List of providers: 22 | http://apn-settings.com/world-apn-list/ 23 | 24 | Please feel free to add to this list 25 | -------------------------------------------------------------------------------- /pi-comm/fona: -------------------------------------------------------------------------------- 1 | # Example PPPD configuration for FONA GPRS connection on Debian/Ubuntu. 2 | 3 | # MUST CHANGE: Change the -T parameter value **** to your network's APN value. 4 | # For example if your APN is 'internet' (without quotes), the line would look like: 5 | connect "/usr/sbin/chat -v -f /etc/chatscripts/gprs -T internet" 6 | 7 | # MUST CHANGE: Uncomment the appropriate serial device for your platform below. 8 | # For Raspberry Pi use /dev/ttyAMA0 by uncommenting the line below: 9 | #/dev/ttyAMA0 10 | /dev/ttyUSB2 11 | 12 | # For BeagleBone Black use /dev/ttyO4 by uncommenting the line below: 13 | #/dev/ttyO4 14 | 15 | # Speed of the serial line. 16 | 115200 17 | 18 | # Assumes that your IP address is allocated dynamically by the ISP. 19 | noipdefault 20 | 21 | # Try to get the name server addresses from the ISP. 22 | usepeerdns 23 | 24 | # Use this connection as the default route to the internet. 25 | defaultroute 26 | 27 | # Makes PPPD "dial again" when the connection is lost. 28 | persist 29 | 30 | # Do not ask the remote to authenticate. 31 | noauth 32 | 33 | # No hardware flow control on the serial link with FONA 34 | nocrtscts 35 | 36 | # No modem control lines with FONA. 37 | local 38 | -------------------------------------------------------------------------------- /pi-comm/gprs: -------------------------------------------------------------------------------- 1 | # You can use this script unmodified to connect to cellular networks. 2 | # The APN is specified in the peers file as the argument of the -T command 3 | # line option of chat(8). 4 | 5 | # For details about the AT commands involved please consult the relevant 6 | # standard: 3GPP TS 27.007 - AT command set for User Equipment (UE). 7 | # (http://www.3gpp.org/ftp/Specs/html-info/27007.htm) 8 | 9 | ABORT BUSY 10 | ABORT VOICE 11 | ABORT "NO CARRIER" 12 | ABORT "NO DIALTONE" 13 | ABORT "NO DIAL TONE" 14 | ABORT "NO ANSWER" 15 | ABORT "DELAYED" 16 | ABORT "ERROR" 17 | 18 | # cease if the modem is not attached to the network yet 19 | ABORT "+CGATT: 0" 20 | 21 | "" AT 22 | TIMEOUT 12 23 | OK ATH 24 | OK ATE1 25 | 26 | # +CPIN provides the SIM card PIN 27 | #OK "AT+CPIN=1234" 28 | 29 | # +CFUN may allow to configure the handset to limit operations to 30 | # GPRS/EDGE/UMTS/etc to save power, but the arguments are not standard 31 | # except for 1 which means "full functionality". 32 | #OK AT+CFUN=1 33 | 34 | OK AT+CGDCONT=1,"IP","\T","",0,0 35 | OK ATD*99# 36 | TIMEOUT 22 37 | CONNECT "" 38 | 39 | --------------------------------------------------------------------------------