#ifndef SMARTCITIZENAMBIENT_cpp #define SMARTCITIZENAMBIENT_cpp #include "SmartCitizenAmbient.h" #define redes 3 #if (redes > 0) char* mySSID[redes] = { "Miguel" ,"hangar_nau3" , "Mi$Red" }; char* myPassword[redes] = { "FINALFANTASY" , "m1cr0fug4s" , "FINALFANTASY" }; char* wifiEncript[redes] = { WPA2 , WPA2 , WPA2 }; char* antennaExt[redes] = { INT_ANT ,INT_ANT , INT_ANT }; //EXT_ANT // char* mySSID[redes] = { "Red1" , "Red2" , "Red3" }; // char* myPassword[redes] = { "Pass1" , "Pass2" , "Pass3" }; // char* wifiEncript[redes] = { WPA2 , WPA2 , WPA2 }; // char* antennaExt[redes] = { INT_ANT , INT_ANT , INT_ANT }; //EXT_ANT #endif char* WEB[10]={ "data.smartcitizen.me", "PUT /add HTTP/1.1 \n", "Host: data.smartcitizen.me \n", "User-Agent: SmartCitizen \n", "X-SmartCitizenMacADDR: ", " \n", "X-SmartCitizenData: ", /*Servidor de tiempo*/ "GET /datetime HTTP/1.1 \n", "Host: data.smartcitizen.me \n", "User-Agent: SmartCitizen \n\n" }; char* SERVER[11]={ "{\"temp\":\"", "\",\"hum\":\"", "\",\"light\":\"", "\",\"bat\":\"", "\",\"panel\":\"", "\",\"co\":\"", "\",\"no2\":\"", "\",\"noise\":\"", "\",\"nets\":\"", "\",\"timestamp\":\"", "\"}" }; float Rs0 = 0; float Rs1 = 0; #define RES 256 //Resolucion de los potenciometros digitales #if F_CPU == 8000000 #define R1 12 //Kohm #else #define R1 82 //Kohm #endif #define P1 100 //Kohm float k= (RES*(float)R1/100)/1000; //Constante de conversion a tension de los reguladores float kr= ((float)P1*1000)/RES; //Constante de conversion a resistencia de potenciometrosen ohmios static char buffer[buffer_length]; void SmartCitizen::begin() { I2c.begin(); I2c.setSpeed(fast); I2c.timeOut(100); Serial.begin(115200); Serial1.begin(9600); pinMode(IO0, OUTPUT); //VH_MICS5525 pinMode(IO1, OUTPUT); //VH_MICS2710 pinMode(IO2, OUTPUT); //MICS2710_ALTAIMPEDANCIA pinMode(AWAKE, OUTPUT); pinMode(MOSI, OUTPUT); pinMode(SCK, OUTPUT); pinMode(FACTORY, OUTPUT); digitalWrite(IO0, LOW); //VH_MICS5525 digitalWrite(IO1, LOW); //VH_MICS2710 digitalWrite(IO2, LOW); //RADJ_MICS2710 digitalWrite(AWAKE, LOW); digitalWrite(FACTORY, LOW); #if F_CPU == 8000000 pinMode(IO4, OUTPUT); //Si7005 //digitalWrite(IO4, LOW); //Si7005 digitalWrite(IO4, HIGH); //Si7005 #endif } void SmartCitizen::config(){ if (!compareDate(__TIME__, readData(EE_ADDR_TIME_VERSION, 0, 0))) { reset(); #if debuggEnabled Serial.println("Reseteando..."); #endif for(uint16_t i=0; i 0) for(byte i=0; i 8) { if (((check_measures + 1)%10) != 0) check_measures = 0; } else check_measures = 0; writeintEEPROM(EE_ADDR_NUMBER_MEASURES, check_measures); } #define TIMEOUT 10000 boolean SmartCitizen::DHT22(uint8_t pin) { // READ VALUES int rv = dhtRead(pin); if (rv != true) { _lastHumidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered? _lastTemperature = DHTLIB_INVALID_VALUE; // invalid value return rv; } // CONVERT AND STORE _lastHumidity = word(bits[0], bits[1]); if (bits[2] & 0x80) // negative temperature { _lastTemperature = word(bits[2]&0x7F, bits[3]); _lastTemperature *= -1.0; } else { _lastTemperature = word(bits[2], bits[3]); } // TEST CHECKSUM uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3]; if (bits[4] != sum) return false; if ((_lastTemperature == 0)&&(_lastHumidity == 0))return false; return true; } boolean SmartCitizen::dhtRead(uint8_t pin) { // INIT BUFFERVAR TO RECEIVE DATA uint8_t cnt = 7; uint8_t idx = 0; // EMPTY BUFFER for (int i=0; i< 5; i++) bits[i] = 0; // REQUEST SAMPLE pinMode(pin, OUTPUT); digitalWrite(pin, LOW); delay(20); digitalWrite(pin, HIGH); delayMicroseconds(40); pinMode(pin, INPUT); // GET ACKNOWLEDGE or TIMEOUT unsigned int loopCnt = TIMEOUT; while(digitalRead(pin) == LOW) if (loopCnt-- == 0) return false; loopCnt = TIMEOUT; while(digitalRead(pin) == HIGH) if (loopCnt-- == 0) return false; // READ THE OUTPUT - 40 BITS => 5 BYTES for (int i=0; i<40; i++) { loopCnt = TIMEOUT; while(digitalRead(pin) == LOW) if (loopCnt-- == 0) return false; unsigned long t = micros(); loopCnt = TIMEOUT; while(digitalRead(pin) == HIGH) if (loopCnt-- == 0) return false; if ((micros() - t) > 40) bits[idx] |= (1 << cnt); if (cnt == 0) // next byte? { cnt = 7; idx++; } else cnt--; } return true; } int SmartCitizen::getTemperatureC(){ return _lastTemperature; } int SmartCitizen::getHumidity(){ return _lastHumidity; } void SmartCitizen::writeMCP(byte deviceaddress, byte address, int data ) { if (data>RES) data=RES; address = (address<<4)|bitRead(data, 8) ; I2c.write(deviceaddress,address,lowByte(data),false); //configura el dispositivo para medir temperatura } int SmartCitizen::readMCP(int deviceaddress, uint16_t address ) { byte rdata = 0xFF; int data = 0x0000; address=(address<<4)|B00001100; I2c.read(deviceaddress, address, 2, false); //read 2 bytes data = I2c.receive()<<8; data = data | I2c.receive(); return data; } void SmartCitizen::writeVH(byte device, long voltage ) { int data=0; #if F_CPU == 8000000 int temp = (int)(((voltage/0.41)-1000)*k); #else int temp = (int)(((voltage/1.2)-1000)*k); #endif if (temp>RES) data = RES; else if (temp<0) data=0; else data = temp; #if F_CPU == 8000000 writeMCP(MCP1, device, data); #else writeMCP(MCP2, device, data); #endif } float SmartCitizen::readVH(byte device) { int data; #if F_CPU == 8000000 data=readMCP(MCP1, device); float voltage = (data/k + 1000)*0.41; #else data=readMCP(MCP2, device); float voltage = (data/k + 1000)*1.2; #endif return(voltage); } #if F_CPU == 8000000 float SmartCitizen::readCharge() { float resistor = kr*readMCP(MCP3, 0x00)/1000; float current = 1000./(2+((resistor * 10)/(resistor + 10))); #if debuggSCK Serial.print("Resistor : "); Serial.print(resistor); Serial.print(" kOhm, "); Serial.print("Current : "); Serial.print(current); Serial.println(" mA"); #endif return(current); } void SmartCitizen::writeCharge(int current) { if (current < 100) current = 100; else if (current > 500) current = 500; float Rp = (1000./current)-2; float resistor = Rp*10/(10-Rp); writeMCP(MCP3, 0x00, (uint8_t)(resistor*1000/kr)); #if debuggSCK Serial.print("Rp : "); Serial.print(Rp); Serial.print(" kOhm, "); Serial.print("Resistor : "); Serial.print(resistor); Serial.print(" kOhm, "); Serial.print("Current : "); Serial.print(current); Serial.println(" mA"); #endif } #endif void SmartCitizen::writeRL(byte device, long resistor) { int data=0x00; data = (int)(resistor/kr); #if F_CPU == 8000000 writeMCP(MCP1, device + 6, data); #else writeMCP(MCP1, device, data); #endif } float SmartCitizen::readRL(byte device) { #if F_CPU == 8000000 return (kr*readMCP(MCP1, device + 6)); //Devuelve en Ohms #else return (kr*readMCP(MCP1, device)); //Devuelve en Ohms #endif } void SmartCitizen::writeRGAIN(byte device, long resistor) { int data=0x00; data = (int)(resistor/kr); writeMCP(MCP2, device, data); } float SmartCitizen::readRGAIN(byte device) { return (kr*readMCP(MCP2, device)); //Devuelve en Ohms } void SmartCitizen::writeGAIN(long value) { if (value == 100) { writeRGAIN(0x00, 10000); writeRGAIN(0x01, 100000); } else if (value == 1000) { writeRGAIN(0x00, 100000); writeRGAIN(0x01, 100000); } delay(100); } float SmartCitizen::readGAIN() { return (readRGAIN(0x00)/1000)*(readRGAIN(0x01)/10000); } void SmartCitizen::writeEEPROM(uint16_t eeaddress, uint8_t data ) { uint8_t retry = 0; while ((readEEPROM(eeaddress)!=data)&&(retry<10)) { I2c.write(E2PROM, eeaddress, data, true); delay(4); retry++; } } byte SmartCitizen::readEEPROM(uint16_t eeaddress ) { byte data = 0xFF; I2c.read(E2PROM, eeaddress, 1, true); //read 1 byte data = I2c.receive(); return data; } void SmartCitizen::writeintEEPROM(uint16_t eeaddress, uint16_t data ) { writeEEPROM(eeaddress , highByte(data)); writeEEPROM(eeaddress + 1, lowByte(data)); ; } uint16_t SmartCitizen::readintEEPROM(uint16_t eeaddress) { return (readEEPROM(eeaddress)<<8)+ readEEPROM(eeaddress + 1); } char* SmartCitizen::readData(uint16_t eeaddress, uint16_t pos, uint8_t dec) { eeaddress = eeaddress + buffer_length * pos; uint8_t temp = readEEPROM(eeaddress); uint16_t i; for ( i = eeaddress; ((temp!= 0x00)&&(temp<0x7E)&&(temp>0x1F)&&((i - eeaddress)0)) { if ((i - eeaddress)= '0')&&(time[count] <= '9')) { rtc[data_count] =(rtc[data_count]<<4)|(0x0F&time[count]); } else break; count++; } if (data_count == 5) { #if F_CPU == 8000000 uint8_t DATA [8] = { rtc[5] | 0x80, rtc[4], rtc[3], 0x00 ,rtc[2], rtc[1], rtc[0], 0x00 } ; #else uint8_t DATA [8] = { rtc[5], rtc[4], rtc[3], 0x00 ,rtc[2], rtc[1], rtc[0], 0x00 } ; #endif I2c.write(RTC_ADDRESS, 0x00, DATA, 8); // COMMAND return true; } return false; } char* SmartCitizen::RTCtime() { I2c.read(RTC_ADDRESS, (uint16_t)0x00, 7, false); //read 4 bytes uint8_t seconds = (I2c.receive() & 0x7F); uint8_t minutes = I2c.receive(); uint8_t hours = I2c.receive(); I2c.receive(); uint8_t day = I2c.receive(); uint8_t month = I2c.receive(); uint8_t year = I2c.receive(); buffer[0] = '2'; buffer[1] = '0'; buffer[2] = (year>>4) + '0'; buffer[3] = (year&0x0F) + '0'; buffer[4] = '-'; buffer[5] = (month>>4) + '0'; buffer[6] = (month&0x0F) + '0'; buffer[7] = '-'; buffer[8] = (day>>4) + '0'; buffer[9] = (day&0x0F) + '0'; buffer[10] = ' '; buffer[11] = (hours>>4) + '0'; buffer[12] = (hours&0x0F) + '0'; buffer[13] = ':'; buffer[14] = (minutes>>4) + '0'; buffer[15] = (minutes&0x0F) + '0'; buffer[16] = ':'; buffer[17] = (seconds>>4) + '0'; buffer[18] = (seconds&0x0F) + '0'; buffer[19] = 0x00; return buffer; } void SmartCitizen::heat(byte device, int current) { float Rc=Rc0; byte Sensor = S2; if (device == MICS_2710) { Rc=Rc1; Sensor = S3;} float Vc = (float)average(Sensor)*Vcc/1023; //mV float current_measure = Vc/Rc; //mA float Rh = (readVH(device)- Vc)/current_measure; float Vh = (Rh + Rc)*current; writeVH(device, Vh); #if debuggSCK if (device == MICS_2710) Serial.print("MICS2710 corriente: "); else Serial.print("MICS5525 corriente: "); Serial.print(current_measure); Serial.println(" mA"); if (device == MICS_2710) Serial.print("MICS2710 correccion VH: "); else Serial.print("MICS5525 correccion VH: "); Serial.print(readVH(device)); Serial.println(" mV"); Vc = (float)average(Sensor)*Vcc/1023; //mV current_measure = Vc/Rc; //mA if (device == MICS_2710) Serial.print("MICS2710 corriente corregida: "); else Serial.print("MICS5525 corriente corregida: "); Serial.print(current_measure); Serial.println(" mA"); Serial.println("Heating..."); #endif } float SmartCitizen::readMICS(byte device, unsigned long time) { byte Sensor = S0; float VMICS = VMIC0; if (device == MICS_2710) {Sensor = S1; VMICS = VMIC1;} delay(time); //Tiempo de enfriamiento para lectura float RL = readRL(device); //Ohm float VL = ((float)average(Sensor)*Vcc)/1023; //mV float Rs = ((VMICS-VL)/VL)*RL; //Ohm /*Correccion de impedancia de carga*/ if (Rs < 100000) { writeRL(device, Rs); delay(100); RL = readRL(device); //Ohm VL = ((float)average(Sensor)*Vcc)/1023; //mV Rs = ((VMICS-VL)/VL)*RL; //Ohm } #if debuggSCK if (device == MICS_5525) Serial.print("MICS5525 Rs: "); else Serial.print("MICS2710 Rs: "); Serial.print(VL); Serial.print(" mV, "); Serial.print(Rs); Serial.println(" Ohm"); #endif; return Rs; } void SmartCitizen::getMICS(unsigned long time0, unsigned long time1){ /*Correccion de la tension del Heather*/ #if F_CPU == 8000000 writeVH(MICS_5525, 2700); //VH_MICS5525 Inicial digitalWrite(IO0, HIGH); //VH_MICS5525 writeVH(MICS_2710, 1700); //VH_MICS5525 Inicial digitalWrite(IO1, HIGH); //VH_MICS2710 digitalWrite(IO2, LOW); //RADJ_MICS2710 PIN ALTA IMPEDANCIA digitalWrite(IO3, HIGH); //Alimentacion de los MICS #if debuggSCK Serial.println("*******************"); Serial.println("MICS5525 VH a 2700 mV"); Serial.println("MICS2714 VH a 1700 mV"); #endif #else writeVH(MICS_5525, 2400); //VH_MICS5525 Inicial digitalWrite(IO0, HIGH); //VH_MICS5525 writeVH(MICS_2710, 1700); //VH_MICS5525 Inicial digitalWrite(IO1, HIGH); //VH_MICS2710 digitalWrite(IO2, LOW); //RADJ_MICS2710 PIN ALTA IMPEDANCIA #if debuggSCK Serial.println("*******************"); Serial.println("MICS5525 VH a 2400 mV"); Serial.println("MICS2710 VH a 1700 mV"); #endif #endif delay(200); // Tiempo estabilizacion de la alimentacion heat(MICS_5525, 32); //Corriente en mA heat(MICS_2710, 26); //Corriente en mA delay(5000); // Tiempo de heater! writeRL(MICS_5525, 100000); //Inicializacion de la carga del MICS5525 writeRL(MICS_2710, 100000); //Inicializacion de la carga del MICS2710 // #if F_CPU == 16000000 // /*Lectura de datos*/ // digitalWrite(IO0, LOW); //VH_MICS5525 OFF para lectura // // #if debuggSCK // Serial.println("MICS5525 VH OFF "); // #endif // #endif Rs0 = readMICS(MICS_5525, time0); Rs1 = readMICS(MICS_2710, time1 - time0); // #if F_CPU == 16000000 // digitalWrite(IO1, LOW); //VH MICS2710 OFF // #if debuggSCK // Serial.println("MICS2710 VH OFF "); // Serial.println("*******************"); // #endif // #endif } uint16_t SmartCitizen::getPanel(){ uint16_t value = 3*average(PANEL)*Vcc/1023; if (value > 500) value = value + 750; //Tension del diodo de proteccion return value; } uint16_t SmartCitizen::getBattery() { uint16_t temp = average(BAT); #if F_CPU == 8000000 float voltage = Vcc*temp/1023.; voltage = voltage + (voltage/180)*100; #else float voltage = Vcc*temp/1023.; #endif temp = map(voltage, VAL_MIN_BATTERY, VAL_MAX_BATTERY, 0, 1000); if (temp>1000) temp=1000; if (temp<0) temp=0; #if debuggSCK Serial.print("Vbat: "); Serial.print(voltage); Serial.print(" mV, "); Serial.print("Battery level: "); Serial.print(temp/10.); Serial.println(" %"); #endif return temp; } #if F_CPU == 8000000 uint16_t SmartCitizen::readSi7005(uint8_t type){ uint16_t DATA = 1; I2c.write(Temperature,(uint16_t)0x03,type, false); //configura el dispositivo para medir delay(15); while (DATA&0x0001 == 0x0001) { I2c.read(Temperature,(uint16_t)0x00,1, false); //read 1 byte DATA = I2c.receive(); } I2c.read(Temperature,(uint16_t)0x01,2, false); //read 2 bytes DATA = I2c.receive()<<8; if (type == 0x11) DATA = (DATA|I2c.receive())>>2; else if (type == 0x01) DATA = (DATA|I2c.receive())>>4; return DATA; } void SmartCitizen::getSi7005(){ digitalWrite(IO4, LOW); //Si7005 delay(15); _lastTemperature = (((float)readSi7005(0x11)/32)-50)*10; _lastHumidity = (((float)readSi7005(0x01)/16)-24)*10; #if debuggSCK Serial.print("Si7005: "); Serial.print("Temperatura: "); Serial.print(_lastTemperature/10.); Serial.print(" C, Humedad: "); Serial.print(_lastHumidity/10.); Serial.println(" %"); #endif digitalWrite(IO4, HIGH); //Si7005 } uint16_t SmartCitizen::readSHT21(uint8_t type){ uint16_t DATA = 0; I2c.write((uint8_t)Temperature, type); //configura el dispositivo para medir delay(200); I2c.read(Temperature, 3); //read 2 bytes DATA = I2c.receive()<<8; DATA = (DATA|I2c.receive()); DATA &= ~0x0003; return DATA; } void SmartCitizen::getSHT21(){ digitalWrite(IO4, HIGH); //Si7005 _lastTemperature = (-46.85 + 175.72 / 65536.0 * (float)(readSHT21(0xE3)))*10; _lastHumidity = (-6.0 + 125.0 / 65536.0 * (float)(readSHT21(0xE5)))*10; #if debuggSCK Serial.print("SHT21: "); Serial.print("Temperatura: "); Serial.print(_lastTemperature/10.); Serial.print(" C, Humedad: "); Serial.print(_lastHumidity/10.); Serial.println(" %"); #endif } #endif uint16_t SmartCitizen::getLight(){ #if F_CPU == 8000000 uint8_t TIME0 = 0xDA; uint8_t GAIN0 = 0x00; uint8_t DATA [8] = {0x03, TIME0, 0x00 ,0x00, 0x00, 0xFF, 0xFF ,GAIN0} ; uint16_t DATA0 = 0; uint16_t DATA1 = 0; I2c.write(bh1730,0x80|0x00, DATA, 8); // COMMAND I2c.read(bh1730, (uint16_t)0x94, 4, false); //read 4 bytes DATA0 = I2c.receive(); DATA0=DATA0|(I2c.receive()<<8); DATA1 = I2c.receive(); DATA1=DATA1|(I2c.receive()<<8); uint8_t Gain = 0x00; if (GAIN0 == 0x00) Gain = 1; else if (GAIN0 == 0x01) Gain = 2; else if (GAIN0 == 0x02) Gain = 64; else if (GAIN0 == 0x03) Gain = 128; float ITIME = (256- TIME0)*2.7; float Lx = 0; float cons = (Gain * 100) / ITIME; float comp = (float)DATA1/DATA0; if (comp<0.26) Lx = ( 1.290*DATA0 - 2.733*DATA1 ) / cons; else if (comp < 0.55) Lx = ( 0.795*DATA0 - 0.859*DATA1 ) / cons; else if (comp < 1.09) Lx = ( 0.510*DATA0 - 0.345*DATA1 ) / cons; else if (comp < 2.13) Lx = ( 0.276*DATA0 - 0.130*DATA1 ) / cons; else Lx=0; #if debuggSCK // Serial.print(DATA0); // Serial.print(' '); // Serial.print(DATA1); // Serial.print(' '); // Serial.print(comp); // Serial.print(' '); // Serial.print(Gain); // Serial.print(' '); // Serial.print(ITIME); // Serial.print(' '); // Serial.print(cons); // Serial.print(' '); Serial.print("BH1730: "); Serial.print(Lx); Serial.println(" Lx"); #endif return Lx*10; #else int temp = map(average(S5), 0, 1023, 0, 1000); if (temp>1000) temp=1000; if (temp<0) temp=0; return temp; #endif } unsigned int SmartCitizen::getNoise() { unsigned long temp = 0; int n = 100; #if F_CPU == 8000000 writeGAIN(1000); delay(100); #else digitalWrite(IO1, HIGH); //VH_MICS2710 delay(500); // LE DAMOS TIEMPO A LA FUENTE Y QUE DESAPAREZCA EL TRANSITORIO #endif float mVRaw = (float)((analogRead(S4))/1023.)*Vcc; float dB = 0; #if F_CPU == 8000000 if (mVRaw > 2000) { writeGAIN(100); delay(100); mVRaw = (float)((analogRead(S4))/1023.)*Vcc; } float GAIN = readGAIN(); if (GAIN == 1000) { if (mVRaw <= 400) dB = 2.4569*log(mVRaw) + 49.838; else dB = 8.9354*log(mVRaw) + 10.629; } else if (GAIN < 1000) dB = 5.2995*log(mVRaw) + 51.704; #else dB = 9.7*log( (mVRaw*200)/1000. ) + 40; // calibracion para ruido rosa // energia constante por octava #endif if(mVRaw == 0) dB = 50; // minimo con la resolucion actual! //mVRaw = (float)((float)(average(S4))/1023)*Vcc; #if debuggSCK Serial.print("nOISE mV = "); Serial.print(mVRaw); Serial.print(" - nOISE dB = "); Serial.println(dB); #endif #if F_CPU > 8000000 digitalWrite(IO1, LOW); //VH_MICS2710 #endif //return max_mVRaw; return dB*100; } unsigned long SmartCitizen::getCO() { return Rs0; } unsigned long SmartCitizen::getNO2() { return Rs1; } void SmartCitizen::updateSensors(byte mode) { checkData(); uint16_t pos = readintEEPROM(EE_ADDR_NUMBER_MEASURES); uint16_t MAX = 800; if ((mode == 2)||(mode == 4)||(pos >= MAX)) { writeintEEPROM(EE_ADDR_NUMBER_MEASURES, 0x0000); pos = 0; } boolean ok_read = false; byte retry = 0; if (pos > 0) pos = pos + 1; #if F_CPU == 8000000 #if SensorModel == 1 getSHT21(); #else #if SensorModel == 2 getSi7005(); #endif #endif ok_read = true; #else Timer1.stop(); while ((!ok_read)&&(retry<5)) { ok_read = DHT22(IO3); retry++; if (!ok_read){ /*Serial.println("FAIL!");*/ delay(3000);} //else Serial.println("OK!"); } Timer1.initialize(500); // set a timer of length 1000000 microseconds (or 1 sec - or 1Hz) #endif if (ok_read ) { writeData(DEFAULT_ADDR_MEASURES, pos + 0, itoa(getTemperatureC())); // C writeData(DEFAULT_ADDR_MEASURES, pos + 1, itoa(getHumidity())); // % } else { writeData(DEFAULT_ADDR_MEASURES, pos + 0, readData(DEFAULT_ADDR_MEASURES, 0, 0)); // C writeData(DEFAULT_ADDR_MEASURES, pos + 1, readData(DEFAULT_ADDR_MEASURES, 1, 0)); // % } writeData(DEFAULT_ADDR_MEASURES, pos + 2, itoa(getLight())); //mV writeData(DEFAULT_ADDR_MEASURES, pos + 3, itoa(getBattery())); //% writeData(DEFAULT_ADDR_MEASURES, pos + 4, itoa(getPanel())); // % if ((mode == 3)||(mode == 4)) { writeData(DEFAULT_ADDR_MEASURES, pos + 5, "0"); //ppm writeData(DEFAULT_ADDR_MEASURES, pos + 6, "0"); //ppm } else { getMICS(4000, 30000); writeData(DEFAULT_ADDR_MEASURES, pos + 5, itoa(getCO())); //ppm writeData(DEFAULT_ADDR_MEASURES, pos + 6, itoa(getNO2())); //ppm } writeData(DEFAULT_ADDR_MEASURES, pos + 7, itoa(getNoise())); //mV if ((mode == 0)||(mode == 2)||(mode == 4)) { writeData(DEFAULT_ADDR_MEASURES, pos + 8, "0"); //Wifi Nets writeData(DEFAULT_ADDR_MEASURES, pos + 9, RTCtime()); } } boolean SmartCitizen::findInResponse(const char *toMatch, unsigned int timeOut = 1000) { int byteRead; unsigned long timeOutTarget; // in milliseconds for (unsigned int offset = 0; offset < strlen(toMatch); offset++) { timeOutTarget = millis() + timeOut; // Doesn't handle timer wrapping while (!Serial1.available()) { // Wait, with optional time out. if (timeOut > 0) { if (millis() > timeOutTarget) { return false; } } delay(1); // This seems to improve reliability slightly } byteRead = Serial1.read(); //Serial.print((char)byteRead); delay(1); // Removing logging may affect timing slightly if (byteRead != toMatch[offset]) { offset = 0; // Ignore character read if it's not a match for the start of the string if (byteRead != toMatch[offset]) { offset = -1; } continue; } } return true; } void SmartCitizen::skipRemainderOfResponse(unsigned int timeOut) { unsigned long time = millis(); while (((millis()-time) // Specify the channel to create network sendCommand(F("set wlan ssid "), true); // Set up network broadcast SSID sendCommand(ssid); sendCommand(F("set ip dhcp 4")); // Enable DHCP server sendCommand(F("set ip address 192.168.0.1")); // Specify the IP address sendCommand(F("set ip net 255.255.255.0")); // Specify the subnet mask sendCommand(F("set ip gateway 192.168.0.1")); // Specify the gateway sendCommand(F("save"), false, "Storing in config"); // Store settings sendCommand(F("reboot"), false, "*READY*"); // Reboot the module in AP mode } } boolean SmartCitizen::ready() { if(!enterCommandMode()) { Serial1.begin(115200); if(enterCommandMode()) reset(); Serial1.begin(9600); } if (enterCommandMode()) { Serial1.println("join"); if (findInResponse("Associated!", 8000)) { skipRemainderOfResponse(3000); exitCommandMode(); return(true); } } else return(false); } boolean SmartCitizen::open(const char *addr, int port) { if (connected) { close(); } if (enterCommandMode()) { sendCommand(F("open "), true); sendCommand(addr, true); Serial1.print(" "); Serial1.print(port); if (sendCommand("", false, "*OPEN*")) { connected = true; return true; } else return false; } enterCommandMode(); return false; } boolean SmartCitizen::isConnected() { return connected; } boolean SmartCitizen::close() { if (!connected) { return true; } if (sendCommand(F("close"), false, "*CLOS*")) { connected = false; return true; } connected = false; return false; } #define MAC_ADDRESS_BUFFER_SIZE 18 // "FF:FF:FF:FF:FF:FF\0" char* SmartCitizen::mac() { if (enterCommandMode()) { if (sendCommand(F("get mac"), false, "Mac Addr=")) { char newChar; byte offset = 0; while (offset < MAC_ADDRESS_BUFFER_SIZE) { if (Serial1.available()) { newChar = Serial1.read(); //Serial.println(newChar); if ((newChar == '\n')||(newChar < '0')) { buffer[offset] = '\x00'; break; } else if (newChar != -1) { buffer[offset] = newChar; offset++; } } } buffer[MAC_ADDRESS_BUFFER_SIZE-1] = '\x00'; exitCommandMode(); } } return buffer; } char* SmartCitizen::id() { char* temp = mac(); byte len = strlen(temp); byte j = 4; buffer[0] = 'S'; buffer[1] = 'C'; buffer[2] = 'K'; buffer[3] = '_'; for(byte i=12; i2) buffer[offset]=':'; else buffer[offset]=' '; count++; } else buffer[offset] = newChar; offset++; } } } } } if (isConnected()) { close(); } exitCommandMode(); } if (!ok) { buffer[0] = '#'; buffer[1] = 0x00; //Serial.println("Fail!!"); } return buffer; } #define SCAN_BUFFER_SIZE 4 char* SmartCitizen::scan() { if (enterCommandMode()) { if (sendCommand(F("scan"), false, "Found ")) { char newChar; byte offset = 0; while (offset < SCAN_BUFFER_SIZE) { if (Serial1.available()) { newChar = Serial1.read(); if ((newChar == '\r')||(newChar < '0')) { buffer[offset] = '\x00'; break; } else if (newChar != -1) { buffer[offset] = newChar; offset++; } } } buffer[SCAN_BUFFER_SIZE-1] = '\x00'; findInResponse("END:\r\n", 2000); exitCommandMode(); } } return buffer; } char* SmartCitizen::itoa(uint32_t number) { byte count = 0; uint32_t temp = number; while ((temp/10)!=0) { temp = temp/10; count++; } int i; for (i = count; i>=0; i--) { buffer[i] = number%10 + '0'; number = number/10; } buffer[count + 1] = 0x00; return buffer; } #define numbers_retry 5 boolean SmartCitizen::server_connect() { uint16_t pos = readintEEPROM(EE_ADDR_NUMBER_MEASURES); writeData(DEFAULT_ADDR_MEASURES, pos + 1, scan()); //Wifi Nets writeData(DEFAULT_ADDR_MEASURES, pos + 2, WIFItime()); checkData(); //Volvemos a verificar si datos correctos return server_reconnect(); } boolean SmartCitizen::server_reconnect() { char* mac_Address = mac(); int retry = 0; boolean ok = false; while ((!ok)&&(retry= numbers_retry) return ok; } } for (byte i = 1; i<5; i++) Serial1.print(WEB[i]); Serial1.print(mac_Address); for (byte i = 5; i<7; i++) Serial1.print(WEB[i]); return ok; } void SmartCitizen::json_update(uint16_t initial) { uint16_t updates = ((readintEEPROM(EE_ADDR_NUMBER_MEASURES) + 1)/10); if ((initial + POST_MAX) <= updates) updates = initial + POST_MAX; if (updates > 0) { Serial1.print(F("[")); for (uint16_t pending = initial; pending < updates; pending++) { byte i; for (i = 0; i<10; i++) { Serial1.print(SERVER[i]); Serial1.print(readData(DEFAULT_ADDR_MEASURES, i + pending*10, 0)); } Serial1.print(SERVER[i]); if ((updates > 1)&&(pending < (updates-1))) Serial1.print(F(",")); } Serial1.println(F("]")); Serial1.println(); } #if debuggSCK if (updates > 0) { Serial.print(F("[")); for (uint16_t pending = initial; pending < updates; pending++) { byte i; for (i = 0; i<10; i++) { Serial.print(SERVER[i]); Serial.print(readData(DEFAULT_ADDR_MEASURES, i + pending*10, 0)); } Serial.print(SERVER[i]); if ((updates > 1)&&(pending < (updates-1))) Serial.print(F(",")); } Serial.println(F("]")); } #endif } /*TIMER*/ TimerOne Timer1; // preinstatiate ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt { Timer1.isrCallback(); } void TimerOne::initialize(long microseconds) { TCCR1A = 0; // clear control register A TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer setPeriod(microseconds); } #define RESOLUTION 65536 // Timer1 is 16 bit void TimerOne::setPeriod(long microseconds) // AR modified for atomic access { long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2 if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8 else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64 else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256 else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024 else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum oldSREG = SREG; cli(); // Disable interrupts for 16 bit register access ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode SREG = oldSREG; TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock } void TimerOne::attachInterrupt(void (*isr)(), long microseconds) { if(microseconds > 0) setPeriod(microseconds); isrCallback = isr; // register the user's callback with the real ISR TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit // AR - remove sei() - might be running with interrupts disabled (eg inside an ISR), so leave unchanged // sei(); // ensures that interrupts are globally enabled resume(); } void TimerOne::resume() // AR suggested { TCCR1B |= clockSelectBits; } void TimerOne::stop() { TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits } uint8_t I2C::bytesAvailable = 0; uint8_t I2C::bufferIndex = 0; uint8_t I2C::totalBytes = 0; uint16_t I2C::timeOutDelay = 0; I2C::I2C() { } /*I2C*/ void I2C::begin() { #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) // activate internal pull-ups for twi // as per note from atmega8 manual pg167 sbi(PORTC, 4); sbi(PORTC, 5); #else // activate internal pull-ups for twi // as per note from atmega128 manual pg204 sbi(PORTD, 0); sbi(PORTD, 1); #endif // initialize twi prescaler and bit rate cbi(TWSR, TWPS0); cbi(TWSR, TWPS1); TWBR = ((F_CPU / 100000) - 16) / 2; // enable twi module and acks TWCR = _BV(TWEN) | _BV(TWEA); } void I2C::end() { TWCR = 0; } void I2C::timeOut(uint16_t _timeOut) { timeOutDelay = _timeOut; } void I2C::setSpeed(uint8_t _fast) { if(!_fast) { TWBR = ((F_CPU / 100000) - 16) / 2; } else { TWBR = ((F_CPU / 400000) - 16) / 2; } } uint8_t I2C::available() { return(bytesAvailable); } uint8_t I2C::receive() { bufferIndex = totalBytes - bytesAvailable; if(!bytesAvailable) { bufferIndex = 0; return(0); } bytesAvailable--; return(data[bufferIndex]); } /*return values for new functions that use the timeOut feature will now return at what point in the transmission the timeout occurred. Looking at a full communication sequence between a master and slave (transmit data and then readback data) there a total of 7 points in the sequence where a timeout can occur. These are listed below and correspond to the returned value: 1 - Waiting for successful completion of a Start bit 2 - Waiting for ACK/NACK while addressing slave in transmit mode (MT) 3 - Waiting for ACK/NACK while sending data to the slave 4 - Waiting for successful completion of a Repeated Start 5 - Waiting for ACK/NACK while addressing slave in receiver mode (MR) 6 - Waiting for ACK/NACK while receiving data from the slave 7 - Waiting for successful completion of the Stop bit All possible return values: 0 Function executed with no errors 1 - 7 Timeout occurred, see above list 8 - 0xFF See datasheet for exact meaning */ ///////////////////////////////////////////////////// uint8_t I2C::write(uint8_t address, uint8_t registerAddress) { returnStatus = 0; returnStatus = start(); if(returnStatus){return(returnStatus);} returnStatus = sendAddress(SLA_W(address)); if(returnStatus) { if(returnStatus == 1){return(2);} return(returnStatus); } returnStatus = sendByte(registerAddress); if(returnStatus) { if(returnStatus == 1){return(3);} return(returnStatus); } returnStatus = stop(); if(returnStatus) { if(returnStatus == 1){return(7);} return(returnStatus); } return(returnStatus); } uint8_t I2C::write(int address, int registerAddress) { return(write((uint8_t) address, (uint8_t) registerAddress)); } uint8_t I2C::write(uint8_t address, uint16_t registerAddress, uint8_t data, boolean mode) { returnStatus = 0; returnStatus = start(); if(returnStatus){return(returnStatus);} returnStatus = sendAddress(SLA_W(address)); if(returnStatus) { if(returnStatus == 1){return(2);} return(returnStatus); } if (!mode) returnStatus = sendByte(registerAddress); else { returnStatus = sendByte((registerAddress >> 8) & 0x00FF); returnStatus = sendByte(registerAddress & 0x00FF); } if(returnStatus) { if(returnStatus == 1){return(3);} return(returnStatus); } returnStatus = sendByte(data); if(returnStatus) { if(returnStatus == 1){return(3);} return(returnStatus); } returnStatus = stop(); if(returnStatus) { if(returnStatus == 1){return(7);} return(returnStatus); } return(returnStatus); } uint8_t I2C::write(int address, int registerAddress, int data) { return(write((uint8_t) address, (uint8_t) registerAddress, (uint8_t) data)); } uint8_t I2C::write(uint8_t address, uint8_t registerAddress, char *data) { uint8_t bufferLength = strlen(data); returnStatus = 0; returnStatus = write(address, registerAddress, (uint8_t*)data, bufferLength); return(returnStatus); } uint8_t I2C::write(uint8_t address, uint8_t registerAddress, uint8_t *data, uint8_t numberBytes) { returnStatus = 0; returnStatus = start(); if(returnStatus){return(returnStatus);} returnStatus = sendAddress(SLA_W(address)); if(returnStatus) { if(returnStatus == 1){return(2);} return(returnStatus); } returnStatus = sendByte(registerAddress); if(returnStatus) { if(returnStatus == 1){return(3);} return(returnStatus); } for (uint8_t i = 0; i < numberBytes; i++) { returnStatus = sendByte(data[i]); if(returnStatus) { if(returnStatus == 1){return(3);} return(returnStatus); } } returnStatus = stop(); if(returnStatus) { if(returnStatus == 1){return(7);} return(returnStatus); } return(returnStatus); } uint8_t I2C::read(int address, int numberBytes) { return(read((uint8_t) address, (uint8_t) numberBytes)); } uint8_t I2C::read(uint8_t address, uint8_t numberBytes) { bytesAvailable = 0; bufferIndex = 0; if(numberBytes == 0){numberBytes++;} nack = numberBytes - 1; returnStatus = 0; returnStatus = start(); if(returnStatus){return(returnStatus);} returnStatus = sendAddress(SLA_R(address)); if(returnStatus) { if(returnStatus == 1){return(5);} return(returnStatus); } for(uint8_t i = 0; i < numberBytes; i++) { if( i == nack ) { returnStatus = receiveByte(0); if(returnStatus == 1){return(6);} if(returnStatus != MR_DATA_NACK){return(returnStatus);} } else { returnStatus = receiveByte(1); if(returnStatus == 1){return(6);} if(returnStatus != MR_DATA_ACK){return(returnStatus);} } data[i] = TWDR; bytesAvailable = i+1; totalBytes = i+1; } returnStatus = stop(); if(returnStatus) { if(returnStatus == 1){return(7);} return(returnStatus); } return(returnStatus); } uint8_t I2C::read(int address, int registerAddress, int numberBytes) { return(read((uint8_t) address, (uint8_t) registerAddress, (uint8_t) numberBytes)); } uint8_t I2C::read(uint8_t address, uint16_t registerAddress, uint8_t numberBytes, boolean mode) { bytesAvailable = 0; bufferIndex = 0; if(numberBytes == 0){numberBytes++;} nack = numberBytes - 1; returnStatus = 0; returnStatus = start(); if(returnStatus){return(returnStatus);} returnStatus = sendAddress(SLA_W(address)); if(returnStatus) { if(returnStatus == 1){return(2);} return(returnStatus); } if (!mode) returnStatus = sendByte(registerAddress); else { returnStatus = sendByte((registerAddress >> 8) & 0x00FF); returnStatus = sendByte(registerAddress & 0x00FF); } if(returnStatus) { if(returnStatus == 1){return(3);} return(returnStatus); } returnStatus = start(); if(returnStatus) { if(returnStatus == 1){return(4);} return(returnStatus); } returnStatus = sendAddress(SLA_R(address)); if(returnStatus) { if(returnStatus == 1){return(5);} return(returnStatus); } for(uint8_t i = 0; i < numberBytes; i++) { if( i == nack ) { returnStatus = receiveByte(0); if(returnStatus == 1){return(6);} if(returnStatus != MR_DATA_NACK){return(returnStatus);} } else { returnStatus = receiveByte(1); if(returnStatus == 1){return(6);} if(returnStatus != MR_DATA_ACK){return(returnStatus);} } data[i] = TWDR; bytesAvailable = i+1; totalBytes = i+1; } returnStatus = stop(); if(returnStatus) { if(returnStatus == 1){return(7);} return(returnStatus); } return(returnStatus); } uint8_t I2C::read(uint8_t address, uint8_t numberBytes, uint8_t *dataBuffer) { bytesAvailable = 0; bufferIndex = 0; if(numberBytes == 0){numberBytes++;} nack = numberBytes - 1; returnStatus = 0; returnStatus = start(); if(returnStatus){return(returnStatus);} returnStatus = sendAddress(SLA_R(address)); if(returnStatus) { if(returnStatus == 1){return(5);} return(returnStatus); } for(uint8_t i = 0; i < numberBytes; i++) { if( i == nack ) { returnStatus = receiveByte(0); if(returnStatus == 1){return(6);} if(returnStatus != MR_DATA_NACK){return(returnStatus);} } else { returnStatus = receiveByte(1); if(returnStatus == 1){return(6);} if(returnStatus != MR_DATA_ACK){return(returnStatus);} } dataBuffer[i] = TWDR; bytesAvailable = i+1; totalBytes = i+1; } returnStatus = stop(); if(returnStatus) { if(returnStatus == 1){return(7);} return(returnStatus); } return(returnStatus); } uint8_t I2C::read(uint8_t address, uint8_t registerAddress, uint8_t numberBytes, uint8_t *dataBuffer) { bytesAvailable = 0; bufferIndex = 0; if(numberBytes == 0){numberBytes++;} nack = numberBytes - 1; returnStatus = 0; returnStatus = start(); if(returnStatus){return(returnStatus);} returnStatus = sendAddress(SLA_W(address)); if(returnStatus) { if(returnStatus == 1){return(2);} return(returnStatus); } returnStatus = sendByte(registerAddress); if(returnStatus) { if(returnStatus == 1){return(3);} return(returnStatus); } returnStatus = start(); if(returnStatus) { if(returnStatus == 1){return(4);} return(returnStatus); } returnStatus = sendAddress(SLA_R(address)); if(returnStatus) { if(returnStatus == 1){return(5);} return(returnStatus); } for(uint8_t i = 0; i < numberBytes; i++) { if( i == nack ) { returnStatus = receiveByte(0); if(returnStatus == 1){return(6);} if(returnStatus != MR_DATA_NACK){return(returnStatus);} } else { returnStatus = receiveByte(1); if(returnStatus == 1){return(6);} if(returnStatus != MR_DATA_ACK){return(returnStatus);} } dataBuffer[i] = TWDR; bytesAvailable = i+1; totalBytes = i+1; } returnStatus = stop(); if(returnStatus) { if(returnStatus == 1){return(7);} return(returnStatus); } return(returnStatus); } /////////////// Private Methods //////////////////////////////////////// uint8_t I2C::start() { unsigned long startingTime = millis(); TWCR = (1<= timeOutDelay) { lockUp(); return(1); } } if ((TWI_STATUS == START) || (TWI_STATUS == REPEATED_START)) { return(0); } if (TWI_STATUS == LOST_ARBTRTN) { uint8_t bufferedStatus = TWI_STATUS; lockUp(); return(bufferedStatus); } return(TWI_STATUS); } uint8_t I2C::sendAddress(uint8_t i2cAddress) { TWDR = i2cAddress; unsigned long startingTime = millis(); TWCR = (1<= timeOutDelay) { lockUp(); return(1); } } if ((TWI_STATUS == MT_SLA_ACK) || (TWI_STATUS == MR_SLA_ACK)) { return(0); } uint8_t bufferedStatus = TWI_STATUS; if ((TWI_STATUS == MT_SLA_NACK) || (TWI_STATUS == MR_SLA_NACK)) { stop(); return(bufferedStatus); } else { lockUp(); return(bufferedStatus); } } uint8_t I2C::sendByte(uint8_t i2cData) { TWDR = i2cData; unsigned long startingTime = millis(); TWCR = (1<= timeOutDelay) { lockUp(); return(1); } } if (TWI_STATUS == MT_DATA_ACK) { return(0); } uint8_t bufferedStatus = TWI_STATUS; if (TWI_STATUS == MT_DATA_NACK) { stop(); return(bufferedStatus); } else { lockUp(); return(bufferedStatus); } } uint8_t I2C::receiveByte(uint8_t ack) { unsigned long startingTime = millis(); if(ack) { TWCR = (1<= timeOutDelay) { lockUp(); return(1); } } if (TWI_STATUS == LOST_ARBTRTN) { uint8_t bufferedStatus = TWI_STATUS; lockUp(); return(bufferedStatus); } return(TWI_STATUS); } uint8_t I2C::stop() { unsigned long startingTime = millis(); TWCR = (1<= timeOutDelay) { lockUp(); return(1); } } return(0); } void I2C::lockUp() { TWCR = 0; //releases SDA and SCL lines to high impedance TWCR = _BV(TWEN) | _BV(TWEA); //reinitialize TWI } I2C I2c = I2C(); #endif