├── Readme.md ├── examples ├── HttpExample.ino ├── IrrigationStationExample.ino ├── WeatherStationExample.ino └── utils │ ├── arducam.h │ ├── logger.h │ ├── sensor.h │ └── valve.h ├── library.properties └── src ├── Ftp.cpp ├── Ftp.h ├── GPRS.cpp ├── GPRS.h ├── Geo.cpp ├── Geo.h ├── Http.cpp ├── Http.h ├── Parser.cpp ├── Parser.h ├── Result.h ├── Sim800.cpp └── Sim800.h /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=58Y36H29935PW&item_name=Support+me+to+continue+developing+features¤cy_code=EUR&source=url) 3 | 4 | # Arduino SIM800L library 5 | A smart HTTP & FTP library based on Seeeduino that implements the AT HTTP commands to perform GET and POST requests to a JSON API as well as FTP uploads. 6 | 7 | ## Support 8 | * Your board has to support the standard SoftwareSerial library. It doesn't work with HardwareSerial based boards for the moment. 9 | * The API response format has to be a valid JSON. 10 | * The library has been tested against Arduino Uno and Arduino Nano. 11 | 12 | ## Instalation 13 | Download the ZIP library and then import it: Sketch -> Include Library -> Add .ZIP Library ... 14 | 15 | ## Quick start! 16 | 17 | How to do a GET request! :+1: 18 | 19 | ``` c++ 20 | unsigned int RX_PIN = 7; 21 | unsigned int TX_PIN = 8; 22 | unsigned int RST_PIN = 12; 23 | 24 | const char BEARER[] PROGMEM = "gprs-service.com"; 25 | 26 | HTTP http(9600, RX_PIN, TX_PIN, RST_PIN); 27 | http.connect(BEARER); 28 | 29 | char response[256]; 30 | Result result = http.get("your.api.com", response); 31 | 32 | Serial.println(response); 33 | 34 | http.disconnect(); 35 | 36 | ``` 37 | 38 | How to do a POST request! :+1: 39 | 40 | ``` c++ 41 | unsigned int RX_PIN = 7; 42 | unsigned int TX_PIN = 8; 43 | unsigned int RST_PIN = 12; 44 | const char BEARER[] PROGMEM = "gprs-service.com"; 45 | 46 | HTTP http(9600, RX_PIN, TX_PIN, RST_PIN); 47 | http.connect(BEARER); 48 | 49 | char response[256]; 50 | Result result = http.post("your.api.com", "{\"date\":\"12345678\"}", response); 51 | 52 | Serial.println(response); 53 | 54 | http.disconnect(); 55 | ``` 56 | 57 | How to do a FTP upload! :+1: 58 | 59 | ``` c++ 60 | unsigned int RX_PIN = 7; 61 | unsigned int TX_PIN = 8; 62 | unsigned int RST_PIN = 12; 63 | const char BEARER[] PROGMEM = "gprs-service.com"; 64 | const char FTP_SERVER[] PROGMEM = "ftp.server"; 65 | const char FTP_USER[] PROGMEM = "user"; 66 | const char FTP_PASS[] PROGMEM = "pass"; 67 | 68 | FTP ftp(9600, RX_PIN, TX_PIN, RST_PIN); 69 | ftp.putBegin(BEARER, "example.txt", FTP_SERVER, FTP_USER, FTP_PASS); 70 | ftp.putWrite("hello!", sizeof("hello!")); 71 | ftp.putEnd(); 72 | 73 | ``` 74 | 75 | I suggest the [ArduinoJSON](https://github.com/bblanchon/ArduinoJson) library for parsing the JSON response, then you can play with the values easily. 76 | 77 | ## HTTP. How it works? 78 | In order to perform a request, the library follows these steps: 79 | 80 | ##### Configure Bearer: 81 | 82 | - AT+CREG? -> try until 0,1 (connected to the network) 83 | - AT+SAPBR=3,1,"Contype","GPRS" -> wait for OK 84 | - AT+SAPBR=3,1,"APN","movistar.es" -> wait for OK 85 | - AT+SAPBR=1,1 -> wait for OK 86 | 87 | ##### HTTP GET: 88 | 89 | - AT+HTTPINIT -> wait for OK 90 | - AT+HTTPPARA="CID",1 -> wait for OK 91 | - AT+HTTPPARA="URL","your.api.com"-> wait for OK 92 | - AT+HTTPSSL=0 -> wait for OK (1 when URL starts with "https://") 93 | - AT+HTTPACTION=0 -> wait for 200 94 | - AT+HTTPREAD -> read buffer and parse it 95 | - AT+HTTPTERM -> wait for OK 96 | - AT+SAPBR=0,1 97 | 98 | ##### HTTP POST: 99 | - AT+HTTPINIT -> wait for OK 100 | - AT+HTTPPARA="CID",1 -> wait for OK 101 | - AT+HTTPPARA="URL","your.api.com" -> wait for OK 102 | 103 | For example, if we have this body: {"location_id": 238, "fill_percent": 90} 104 | 105 | - AT+HTTPPARA="CONTENT","application/json" 106 | - AT+HTTPDATA=strlen(body),10000 -> wait for DOWNLOAD, then write the body and wait 10000 107 | - AT+HTTPSSL=0 -> wait for OK (1 when URL starts with "https://") 108 | - AT+HTTPACTION=1 -> wait for ,200, 109 | - AT+HTTPREAD -> read buffer and parse it 110 | - AT+HTTPTERM -> wait for OK 111 | - AT+SAPBR=0,1 112 | 113 | ## Future improvements 114 | 115 | - Support of HardwareSerial. 116 | - Support of more content types, not only JSON (application/json). 117 | 118 | 119 | ## Development 120 | - Lint: `cppcheck --enable=all .` -------------------------------------------------------------------------------- /examples/HttpExample.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define RST_PIN 8 5 | #define RX_PIN 10 6 | #define TX_PIN 9 7 | 8 | const char BEARER[] PROGMEM = "your.mobile.service.provider.apn"; 9 | 10 | // the setup routine runs once when you press reset: 11 | void setup() 12 | { 13 | Serial.begin(9600); 14 | while (!Serial) 15 | ; 16 | Serial.println("Starting!"); 17 | } 18 | 19 | // the loop routine runs over and over again forever: 20 | void loop() 21 | { 22 | HTTP http(9600, RX_PIN, TX_PIN, RST_PIN); 23 | 24 | char response[32]; 25 | char body[90]; 26 | Result result; 27 | 28 | // Notice the bearer must be a pointer to the PROGMEM 29 | result = http.connect(BEARER); 30 | Serial.print(F("HTTP connect: ")); 31 | Serial.println(result); 32 | 33 | sprintf(body, "{\"title\": \"%s\", \"body\": \"%s\", \"user_id\": \"%d\"}", "Arduino", "Test", 1); 34 | result = http.post("https://your.api", body, response); 35 | Serial.print(F("HTTP POST: ")); 36 | Serial.println(result); 37 | if (result == SUCCESS) 38 | { 39 | Serial.println(response); 40 | StaticJsonBuffer<64> jsonBuffer; 41 | JsonObject &root = jsonBuffer.parseObject(response); 42 | 43 | const char *id = root[F("id")]; 44 | Serial.print(F("ID: ")); 45 | Serial.println(id); 46 | } 47 | 48 | result = http.get("https://your.api", response); 49 | Serial.print(F("HTTP GET: ")); 50 | Serial.println(result); 51 | if (result == SUCCESS) 52 | { 53 | Serial.println(response); 54 | StaticJsonBuffer<64> jsonBuffer; 55 | JsonObject &root = jsonBuffer.parseObject(response); 56 | 57 | const char *id = root[F("id")]; 58 | Serial.print(F("ID: ")); 59 | Serial.println(id); 60 | } 61 | 62 | Serial.print(F("HTTP disconnect: ")); 63 | Serial.print(http.disconnect()); 64 | } 65 | -------------------------------------------------------------------------------- /examples/IrrigationStationExample.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define BATTERY_PIN 2 5 | #define PROBE_PIN 6 6 | #define PUMP_MOFSET_PIN 15 // Used to switch the power of the pump with the MOFSET 7 | #define LED_PIN 17 8 | #define TEMP_HUM_PIN 18 9 | #define VIN_PROBE_PIN 19 10 | 11 | DHT dht(TEMP_HUM_PIN, DHT11); 12 | 13 | unsigned long oneMinuteMs = 60000; 14 | unsigned long oneHourMs = 3600000; 15 | 16 | unsigned long irrigationTimeMs = 10000; 17 | unsigned long sleepTimeSeconds = 24 * oneHourMs / 1000; 18 | unsigned int irrigationLoops = 6; 19 | const int dryThreshold = 942; 20 | /* 21 | * >= 13 volts = 100% 22 | * 12.75 volts 90% 23 | * 12.5 volts = 80% 24 | * 12.3 volts = 70% 25 | * Don't go bellow 70% 26 | */ 27 | float minBatteryVoltage = 12.5; 28 | 29 | // Set to true to test the moisture 30 | bool test = false; 31 | bool noWater = false; 32 | 33 | void setCPUAt8Mhz(){ 34 | noInterrupts(); 35 | CLKPR = 1< 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "../examples/utils/logger.h" 9 | #include "../examples/utils/valve.h" 10 | #include "../examples/utils/sensor.h" 11 | #include "../examples/utils/arducam.h" 12 | 13 | #define SD_CS_PIN 3 14 | #define RST_PIN 8 15 | #define RX_PIN 10 16 | #define TX_PIN 9 17 | 18 | #define BAUD_RATE 19200 19 | #define MAX_RETRIES 10 20 | 21 | #define CLOSE_VALVE_STATE 0 22 | #define OPEN_VALVE_STATE 1 23 | 24 | const char BEARER[] PROGMEM = "your.bearer"; 25 | const char FTP_SERVER[] PROGMEM = "ftp.server"; 26 | const char FTP_USER[] PROGMEM = "user"; 27 | const char FTP_PASS[] PROGMEM = "pass"; 28 | const char BODY_FORMAT[] PROGMEM = "{\"w\":{\"m\":%d,\"t\":%d,\"h\":%d,\"mv\":%d,\"sv\":%d,\"st\":%d}}"; 29 | const char ENDPOINT[] PROGMEM = "https://your.api.com"; 30 | const char OPEN_VALVE[] PROGMEM = "open-valve"; 31 | const char CLOSE_VALVE[] PROGMEM = "close-valve"; 32 | const char RESET[] PROGMEM = "reset"; 33 | 34 | unsigned long timeToSleep = 0; 35 | unsigned long elapsedTime = 0; 36 | uint8_t retries = 0; 37 | uint8_t currentImage = 0; 38 | bool currentState = CLOSE_VALVE_STATE; 39 | 40 | /* 41 | functions 42 | */ 43 | 44 | void(*reset) (void) = 0; 45 | 46 | void resetArudino(){ 47 | info(F("Reset!")); 48 | delay(1000); 49 | reset(); 50 | } 51 | 52 | void sleep() { 53 | while (elapsedTime <= timeToSleep) { 54 | LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); 55 | elapsedTime += 7000; 56 | } 57 | } 58 | 59 | unsigned int readLipoVoltage() { 60 | HTTP http(BAUD_RATE, RX_PIN, TX_PIN, RST_PIN); 61 | http.wakeUp(); 62 | unsigned int voltage = 0; 63 | for (unsigned int i = 0; i < 10; ++i) { 64 | unsigned int cv = http.readVoltage(); 65 | if (cv > voltage) { 66 | voltage = cv; 67 | } 68 | } 69 | http.sleep(); 70 | return voltage; 71 | } 72 | 73 | unsigned int availableMemory() { 74 | int size = 1024; 75 | byte *buf; 76 | 77 | while ((buf = (byte *) malloc(--size)) == NULL); 78 | free(buf); 79 | 80 | return size; 81 | } 82 | 83 | void uploadFile(const char *filename) { 84 | File dataFile = SD.open(filename); 85 | 86 | if (!dataFile) { 87 | info(F("FTP. File open failed: ")); 88 | info(filename); 89 | return; 90 | } 91 | 92 | FTP ftp(BAUD_RATE, RX_PIN, TX_PIN, RST_PIN); 93 | ftp.wakeUp(); 94 | ftp.putBegin(BEARER, filename, FTP_SERVER, FTP_USER, FTP_PASS); 95 | 96 | unsigned int i; 97 | unsigned int chunkSize = 64; 98 | unsigned int writes = ceil(dataFile.size() / chunkSize); 99 | char buff[chunkSize]; 100 | 101 | while (dataFile.available()) { 102 | i = 0; 103 | while (i < chunkSize) { 104 | buff[i] = dataFile.read(); 105 | ++i; 106 | } 107 | 108 | if (ftp.putWrite(buff, i) != SUCCESS){ 109 | return; 110 | } 111 | writes --; 112 | 113 | info(F("Pending: "), false); 114 | info(writes, false); 115 | info(F("/"), false); 116 | info(ceil(dataFile.size() / chunkSize), true); 117 | } 118 | 119 | ftp.putEnd(); 120 | ftp.sleep(); 121 | dataFile.close(); 122 | } 123 | 124 | Result postEntry(char *response) { 125 | info(F("SRAM: "), false); 126 | info(availableMemory(), true); 127 | 128 | unsigned int temperature = readTemperature(); 129 | unsigned int humidity = readHumidity(); 130 | unsigned int moisture = readMoisture(); 131 | unsigned int litioVoltage = readLitioVoltage(); 132 | unsigned int liPoVoltage = readLipoVoltage(); 133 | 134 | char body[70]; 135 | Result result; 136 | sprintf_P(body, BODY_FORMAT, 137 | moisture, 138 | temperature, 139 | humidity, 140 | litioVoltage, 141 | liPoVoltage, 142 | currentState 143 | ); 144 | info(body); 145 | char endpoint[64]; 146 | strcpy_P(endpoint, ENDPOINT); 147 | info(endpoint); 148 | 149 | HTTP http(BAUD_RATE, RX_PIN, TX_PIN, RST_PIN); 150 | http.wakeUp(); 151 | http.connect(BEARER); 152 | result = http.post(endpoint, body, response); 153 | http.disconnect(); 154 | http.sleep(); 155 | 156 | return result; 157 | } 158 | 159 | void manageGarden() { 160 | char buff[32]; 161 | buildImageName(buff, currentImage); 162 | Serial.println(buff); 163 | Result result = postEntry(buff); 164 | 165 | if (result == SUCCESS) { 166 | info(buff); 167 | StaticJsonBuffer<32> jsonBuffer; 168 | JsonObject& root = jsonBuffer.parseObject(buff); 169 | 170 | if (strcmp_P(root[F("action")], OPEN_VALVE) == 0){ 171 | openValve(); 172 | currentState = OPEN_VALVE_STATE; 173 | } 174 | else if (strcmp_P(root[F("action")], CLOSE_VALVE) == 0){ 175 | closeValve(); 176 | currentState = CLOSE_VALVE_STATE; 177 | } 178 | else if (strcmp_P(root[F("action")], RESET) == 0) { 179 | resetArudino(); 180 | } 181 | 182 | timeToSleep = root[F("value")]; 183 | elapsedTime = 0; 184 | retries = 0; 185 | 186 | buildImageName(buff, currentImage); 187 | if (takePicture(buff)){ 188 | uploadFile(buff); 189 | currentImage++; 190 | } 191 | } 192 | else { 193 | info(F("POST error: "), false); 194 | info(result, true); 195 | retries ++; 196 | if (retries == MAX_RETRIES) resetArudino(); 197 | } 198 | } 199 | 200 | /* 201 | the setup routine runs once when you press reset: 202 | */ 203 | void setup() { 204 | Serial.begin(BAUD_RATE); 205 | while (!Serial); 206 | 207 | // This setup is necessary for the logger and Arducam 208 | if (!SD.begin(SD_CS_PIN)) { 209 | info(F("Error starting SD")); 210 | } 211 | 212 | // This setup is necessary for the Arducam connection 213 | SPI.begin(); 214 | Wire.begin(); 215 | 216 | currentState = CLOSE_VALVE_STATE; 217 | 218 | info(F("Starting!")); 219 | 220 | //openValve(); 221 | //closeValve(); 222 | } 223 | 224 | /* 225 | the loop routine runs over and over again forever: 226 | */ 227 | void loop() { 228 | manageGarden(); 229 | sleep(); 230 | } 231 | -------------------------------------------------------------------------------- /examples/utils/arducam.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARDUCAM_H__ 2 | #define __ARDUCAM_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define FRAMES_NUM 0x00 10 | #define CAM_CS 5 11 | 12 | const char IMG_NAME[] PROGMEM = "%d.jpg"; 13 | 14 | void buildImageName(char *filename, uint8_t currentImage) { 15 | sprintf_P(filename, IMG_NAME, currentImage); 16 | } 17 | 18 | // bool takePicture(const char *imageName) 19 | // { 20 | // // This setup is necessary for the Arducam connection 21 | // SPI.begin(); 22 | // Wire.begin(); 23 | 24 | // // Leave some time to stabilize 25 | // delay(100); 26 | 27 | // // Set the CS to high means this device is not selected 28 | // pinMode(CAM_CS, OUTPUT); 29 | // digitalWrite(CAM_CS, HIGH); 30 | 31 | // ArduCAM myCAM(OV2640, CAM_CS); 32 | 33 | // //Reset the CPLD 34 | // myCAM.write_reg(0x07, 0x80); 35 | // delay(100); 36 | // myCAM.write_reg(0x07, 0x00); 37 | // delay(100); 38 | 39 | // //Change to JPEG capture mode and initialize the OV5640 module 40 | // myCAM.set_format(JPEG); 41 | // myCAM.InitCAM(); 42 | // myCAM.clear_fifo_flag(); 43 | // myCAM.write_reg(ARDUCHIP_FRAMES, FRAMES_NUM); 44 | 45 | // myCAM.flush_fifo(); 46 | // myCAM.clear_fifo_flag(); 47 | 48 | // // Sizes https://github.com/ArduCAM/Arduino/blob/78ccbb131ac17d8f59c154ce41993cd2e083440e/ArduCAM/keywords.txt#L121 49 | // myCAM.OV2640_set_JPEG_size(OV2640_320x240); 50 | 51 | // //Start capture 52 | // myCAM.start_capture(); 53 | // info(F("Start capture")); 54 | 55 | // uint8_t temp = 0, temp_last = 0; 56 | // uint32_t length = 0; 57 | // int i = 0; 58 | 59 | // while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK) && i < 10) 60 | // { 61 | // ++i; 62 | // delay(500); 63 | // } 64 | // i = 0; 65 | 66 | // length = myCAM.read_fifo_length(); 67 | // info(F("The fifo length is:"), FALSE); 68 | // info(length, TRUE); 69 | 70 | // if (length >= MAX_FIFO_SIZE) //8M 71 | // { 72 | // info("Over size."); 73 | // return false; 74 | // } 75 | // if (length <= 0) //0 kb 76 | // { 77 | // info(F("Size is 0.")); 78 | // return false; 79 | // } 80 | 81 | // myCAM.CS_HIGH(); 82 | 83 | // File outFile = SD.open(imageName, O_WRITE | O_CREAT | O_TRUNC); 84 | // if (!outFile) 85 | // { 86 | // info(F("CAM. File open failed: "), FALSE); 87 | // info(imageName); 88 | // return false; 89 | // } 90 | 91 | // myCAM.CS_LOW(); 92 | 93 | // //Read the first dummy byte from FIFO 94 | // temp = myCAM.read_fifo(); 95 | 96 | // //Read JPEG data from FIFO 97 | // while( (temp != 0xD9) | (temp_last != 0xFF) ) 98 | // { 99 | // temp_last = temp; 100 | // //Read one byte from the image 101 | // temp = myCAM.read_fifo(); 102 | 103 | // //Write one byte from the image 104 | // // myCAM.CS_HIGH(); 105 | // outFile.write(temp); 106 | // // myCAM.CS_LOW(); 107 | // } 108 | 109 | // myCAM.CS_HIGH(); 110 | // outFile.close(); 111 | 112 | // info("Finished", FALSE); 113 | 114 | // return true; 115 | // } 116 | 117 | bool takePicture(const char *imageName, uint8_t quality = 0) 118 | { 119 | // This setup is necessary for the Arducam connection 120 | SPI.begin(); 121 | Wire.begin(); 122 | 123 | pinMode(CAM_CS, OUTPUT); 124 | digitalWrite(CAM_CS, HIGH); 125 | 126 | ArduCAM myCAM(OV2640, CAM_CS); 127 | 128 | //Reset the CPLD 129 | myCAM.write_reg(0x07, 0x80); 130 | delay(100); 131 | myCAM.write_reg(0x07, 0x00); 132 | delay(100); 133 | 134 | //Change to JPEG capture mode and initialize the OV5640 module 135 | myCAM.set_format(JPEG); 136 | myCAM.InitCAM(); 137 | myCAM.clear_fifo_flag(); 138 | myCAM.write_reg(ARDUCHIP_FRAMES, FRAMES_NUM); 139 | myCAM.flush_fifo(); 140 | myCAM.clear_fifo_flag(); 141 | 142 | // Sizes https://github.com/ArduCAM/Arduino/blob/78ccbb131ac17d8f59c154ce41993cd2e083440e/ArduCAM/keywords.txt#L121 143 | switch(quality) { 144 | case 0: 145 | myCAM.OV2640_set_JPEG_size(OV2640_320x240); 146 | break; 147 | case 1: 148 | myCAM.OV2640_set_JPEG_size(OV2640_640x480); 149 | break; 150 | case 2: 151 | myCAM.OV2640_set_JPEG_size(OV2640_1024x768); 152 | break; 153 | case 3: 154 | myCAM.OV2640_set_JPEG_size(OV2640_1600x1200); 155 | break; 156 | default: 157 | myCAM.OV2640_set_JPEG_size(OV2640_320x240); 158 | } 159 | 160 | //myCAM.OV2640_set_Light_Mode(Sunny); 161 | myCAM.OV2640_set_Color_Saturation(Saturation2); 162 | myCAM.OV2640_set_Contrast(Contrast2); 163 | 164 | //Start capture 165 | myCAM.start_capture(); 166 | info(F("Start capture")); 167 | 168 | uint8_t temp = 0, temp_last = 0; 169 | uint32_t length = 0; 170 | int i = 0; 171 | File outFile; 172 | uint8_t bufSize = 8; 173 | byte buf[bufSize]; 174 | bool isHeader = false; 175 | bool imageTook = false; 176 | 177 | while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK) && i < 10) 178 | { 179 | ++i; 180 | delay(500); 181 | } 182 | i = 0; 183 | 184 | length = myCAM.read_fifo_length(); 185 | info(F("The fifo length is:"), FALSE); 186 | info(length, TRUE); 187 | 188 | if (length >= MAX_FIFO_SIZE) //8M 189 | { 190 | info("Over size."); 191 | return 0; 192 | } 193 | if (length == 0) //0 kb 194 | { 195 | info(F("Size is 0.")); 196 | return 0; 197 | } 198 | myCAM.CS_LOW(); 199 | myCAM.set_fifo_burst(); 200 | i = 0; 201 | while (length--) 202 | { 203 | temp_last = temp; 204 | temp = SPI.transfer(0x00); 205 | //Read JPEG data from FIFO 206 | if ((temp == 0xD9) && (temp_last == 0xFF)) //If find the end, break while, 207 | { 208 | buf[i++] = temp; //save the last 0XD9 209 | //Write the remain bytes in the buffer 210 | myCAM.CS_HIGH(); 211 | outFile.write(buf, i); 212 | //Close the file 213 | outFile.close(); 214 | info(F("Capture Done!!")); 215 | 216 | isHeader = false; 217 | myCAM.CS_LOW(); 218 | myCAM.set_fifo_burst(); 219 | i = 0; 220 | imageTook = TRUE; 221 | } 222 | 223 | if (isHeader == true) // Write data 224 | { 225 | //Write image data to buffer if not full 226 | if (i < bufSize) 227 | buf[i++] = temp; 228 | else 229 | { 230 | //Write bufSize bytes image data to file 231 | myCAM.CS_HIGH(); 232 | outFile.write(buf, bufSize); 233 | i = 0; 234 | buf[i++] = temp; 235 | myCAM.CS_LOW(); 236 | myCAM.set_fifo_burst(); 237 | } 238 | } 239 | else if ((temp == 0xD8) & (temp_last == 0xFF)) // Start 240 | { 241 | isHeader = true; 242 | myCAM.CS_HIGH(); 243 | 244 | outFile = SD.open(imageName, O_WRITE | O_CREAT | O_TRUNC); 245 | if (!outFile) 246 | { 247 | info(F("CAM. File open failed: "), FALSE); 248 | info(imageName); 249 | 250 | return imageTook; 251 | } 252 | myCAM.CS_LOW(); 253 | myCAM.set_fifo_burst(); 254 | buf[i++] = temp_last; 255 | buf[i++] = temp; 256 | } 257 | } 258 | 259 | myCAM.CS_HIGH(); 260 | //Clear the capture done flag 261 | myCAM.clear_fifo_flag(); 262 | 263 | pinMode(CAM_CS, INPUT); 264 | 265 | return imageTook; 266 | } 267 | 268 | #endif __ARDUCAM_H__ 269 | -------------------------------------------------------------------------------- /examples/utils/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOGGER_H__ 2 | #define __LOGGER_H__ 3 | 4 | //#include 5 | #include 6 | 7 | #define LOG_FILE "l" 8 | 9 | const char LOG_INT[] PROGMEM = "%d"; 10 | 11 | void info(const char *message, bool newLine = true) 12 | { 13 | #ifdef DEBUG 14 | newLine ? Serial.println(message) : Serial.print(message); 15 | #endif 16 | 17 | // File file = SD.open(LOG_FILE, FILE_WRITE); 18 | // if (file) 19 | // { 20 | // newLine ? file.println(message) : file.print(message); 21 | // file.close(); 22 | // } 23 | } 24 | 25 | void info(const __FlashStringHelper *message, bool newLine = true) 26 | { 27 | #ifdef DEBUG 28 | newLine ? Serial.println(message) : Serial.print(message); 29 | #endif 30 | 31 | // File file = SD.open(LOG_FILE, FILE_WRITE); 32 | // if (file) 33 | // { 34 | // newLine ? file.println(message) : file.print(message); 35 | // file.close(); 36 | // } 37 | } 38 | 39 | void info(long message, bool newLine = true) 40 | { 41 | char buffer[10]; 42 | // Use sprintf instead of overrided Serial.print in order to 43 | // save space 44 | sprintf_P(buffer, LOG_INT, message); 45 | return info(buffer, newLine); 46 | } 47 | 48 | #endif __LOGGER_H__ -------------------------------------------------------------------------------- /examples/utils/sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef __SENSOR_H__ 2 | #define __SENSOR_H__ 3 | 4 | #include 5 | #include "HTTP.h" 6 | 7 | #define TEMPERATURE_HUMIDITY_PIN 6 8 | #define MOISTURE_PIN 7 9 | #define DHTTYPE DHT11 10 | 11 | DHT dht(TEMPERATURE_HUMIDITY_PIN, DHTTYPE); 12 | 13 | void initializeSensors(){ 14 | dht.begin(); 15 | pinMode(MOISTURE_PIN, INPUT); 16 | } 17 | 18 | unsigned int readHumidity() 19 | { 20 | unsigned int h = dht.readHumidity(); 21 | byte retry = 0; 22 | while (isnan(h) && retry < 5) 23 | { 24 | delay(250); 25 | h = dht.readHumidity(); 26 | retry ++; 27 | } 28 | return h; 29 | } 30 | 31 | unsigned int readTemperature() 32 | { 33 | unsigned int t = dht.readTemperature(); 34 | byte retry = 0; 35 | while (isnan(t) && retry < 5) 36 | { 37 | delay(250); 38 | t = dht.readTemperature(); 39 | retry ++; 40 | } 41 | return t; 42 | } 43 | 44 | unsigned int readMoisture() 45 | { 46 | /* 47 | Dry 676 - Wet 376 48 | */ 49 | int moisture = 0; 50 | for (uint8_t i = 0; i <5; ++i){ 51 | int current = analogRead(MOISTURE_PIN); 52 | if (current > moisture) moisture = current; 53 | delay(250); 54 | } 55 | return (unsigned int)moisture; 56 | } 57 | 58 | unsigned int readLitioVoltage() 59 | { 60 | // Read 1.1V reference against AVcc 61 | // set the reference to Vcc and the measurement to the internal 1.1V reference 62 | #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 63 | ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 64 | #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) 65 | ADMUX = _BV(MUX5) | _BV(MUX0) ; 66 | #else 67 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 68 | #endif 69 | 70 | delay(2); // Wait for Vref to settle 71 | ADCSRA |= _BV(ADSC); // Start conversion 72 | while (bit_is_set(ADCSRA,ADSC)); // measuring 73 | 74 | uint8_t low = ADCL; // must read ADCL first - it then locks ADCH 75 | uint8_t high = ADCH; // unlocks both 76 | 77 | long result = (high<<8) | low; 78 | 79 | // Taking 1.1 as Vref: Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 80 | // In this example I used the Vref of 1.08 81 | result = 1104840 / result; 82 | return result; // Vcc in millivolts 83 | } 84 | 85 | #endif __SENSOR_H__ 86 | -------------------------------------------------------------------------------- /examples/utils/valve.h: -------------------------------------------------------------------------------- 1 | #ifndef __VALVE_H__ 2 | #define __VALVE_H__ 3 | 4 | #include 5 | #include "logger.h" 6 | 7 | #define VALVE_SWITCH_PIN 4 8 | #define VALVE_OPEN_CLOSE_PIN 2 9 | 10 | void moveValve(byte value) 11 | { 12 | // Switch the solar input to power the valve 13 | pinMode(VALVE_SWITCH_PIN, OUTPUT); 14 | pinMode(VALVE_OPEN_CLOSE_PIN, OUTPUT); 15 | 16 | digitalWrite(VALVE_SWITCH_PIN, LOW); 17 | digitalWrite(VALVE_OPEN_CLOSE_PIN, value); 18 | 19 | delay(15000); 20 | 21 | pinMode(VALVE_OPEN_CLOSE_PIN, INPUT); 22 | pinMode(VALVE_SWITCH_PIN, INPUT); 23 | } 24 | 25 | void openValve() 26 | { 27 | info(F("Open valve")); 28 | moveValve(HIGH); 29 | } 30 | 31 | void closeValve() 32 | { 33 | info(F("Close Valve")); 34 | moveValve(LOW); 35 | } 36 | 37 | #endif __VALVE_H__ -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ArduinoSIM800L 2 | version=0.2 3 | author=Antonio Carrasco 4 | maintainer=Antonio Carrasco 5 | sentence=An efficient and elegant HTTP & FTP library for Arduino 6 | paragraph=ArduinoSIM800L supports ✔ http post requests, ✔ http get requests, ✔ ftp upload, ✔ full interaction with SIM800 and more. 7 | category=Communication 8 | url=https://github.com/carrascoacd/ArduinoSIM800L 9 | architectures=avr 10 | repository=https://github.com/carrascoacd/ArduinoSIM800L 11 | license=MIT -------------------------------------------------------------------------------- /src/Ftp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Ftp.cpp 3 | * Ftp library for the SIM800L board 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include "Ftp.h" 29 | 30 | const char AT_FTPCID[] PROGMEM = "AT+FTPCID=1\r\n"; 31 | const char AT_FTPSERV[] PROGMEM = "AT+FTPSERV=\"%s\"\r\n"; 32 | const char AT_FTPUN[] PROGMEM = "AT+FTPUN=\"%s\"\r\n"; 33 | const char AT_FTPPW[] PROGMEM = "AT+FTPPW=\"%s\"\r\n"; 34 | const char AT_FTPPUTNAME[] PROGMEM = "AT+FTPPUTNAME=\"%s\"\r\n"; 35 | const char AT_FTPPUTPATH[] PROGMEM = "AT+FTPPUTPATH=\"%s\"\r\n"; 36 | const char AT_FTPPUT1[] PROGMEM = "AT+FTPPUT=1\r\n"; 37 | const char AT_FTPPUT2[] PROGMEM = "AT+FTPPUT=2,%d\r\n"; 38 | const char AT_FTPPUT20[] PROGMEM = "AT+FTPPUT=2,0\r\n"; 39 | const char BEARER_PROFILE_GPRS[] PROGMEM = "AT+SAPBR=3,1,\"Contype\",\"GPRS\"\r\n"; 40 | const char BEARER_PROFILE_APN[] PROGMEM = "AT+SAPBR=3,1,\"APN\",\"%s\"\r\n"; 41 | const char QUERY_BEARER[] PROGMEM = "AT+SAPBR=2,1\r\n"; 42 | const char OPEN_GPRS_CONTEXT[] PROGMEM = "AT+SAPBR=1,1\r\n"; 43 | const char CLOSE_GPRS_CONTEXT[] PROGMEM = "AT+SAPBR=0,1\r\n"; 44 | const char REGISTRATION_STATUS[] PROGMEM = "AT+CREG?\r\n"; 45 | const char SLEEP_MODE_2[] PROGMEM = "AT+CSCLK=2\r\n"; 46 | 47 | const char AT_OK[] PROGMEM = "OK"; 48 | const char AT_OK_[] = "OK"; 49 | const char AT_FTPPUT1_RESP[] PROGMEM = "1,1"; 50 | const char AT_FTPPUT2_RESP[] PROGMEM = "+FTPPUT: 2"; 51 | const char AT_FTPPUT20_RESP[] PROGMEM = "1,0"; 52 | 53 | #include "GPRS.h" 54 | 55 | Result FTP::putBegin(const char *apn, 56 | const char *fileName, 57 | const char *server, 58 | const char *usr, 59 | const char *pass, 60 | const char *path) 61 | { 62 | Result result = openGPRSContext(this, apn); 63 | 64 | char buffer[64]; 65 | char tmp[24]; 66 | 67 | delay(10000); 68 | if (sendCmdAndWaitForResp_P(AT_FTPCID, AT_OK, 2000) == FALSE) 69 | return ERROR_FTPCID; 70 | 71 | strcpy_P(tmp, server); 72 | sprintf_P(buffer, AT_FTPSERV, tmp); 73 | if (sendCmdAndWaitForResp(buffer, AT_OK_, 2000) == FALSE) 74 | return ERROR_FTPSERV; 75 | 76 | strcpy_P(tmp, usr); 77 | sprintf_P(buffer, AT_FTPUN, tmp); 78 | if (sendCmdAndWaitForResp(buffer, AT_OK_, 2000) == FALSE) 79 | return ERROR_FTPUN; 80 | 81 | strcpy_P(tmp, pass); 82 | sprintf_P(buffer, AT_FTPPW, tmp); 83 | if (sendCmdAndWaitForResp(buffer, AT_OK_, 2000) == FALSE) 84 | return ERROR_FTPPW; 85 | 86 | sprintf_P(buffer, AT_FTPPUTNAME, fileName); 87 | if (sendCmdAndWaitForResp(buffer, AT_OK_, 2000) == FALSE) 88 | return ERROR_FTPPUTNAME; 89 | 90 | sprintf_P(buffer, AT_FTPPUTPATH, path); 91 | if (sendCmdAndWaitForResp(buffer, AT_OK_, 2000) == FALSE) 92 | return ERROR_FTPPUTPATH; 93 | 94 | if (sendCmdAndWaitForResp_P(AT_FTPPUT1, AT_FTPPUT1_RESP, 10000) == FALSE) 95 | return ERROR_FTPPUT1; 96 | 97 | return result; 98 | } 99 | 100 | Result FTP::putWrite(const char *data, unsigned int size) 101 | { 102 | Result result = SUCCESS; 103 | 104 | uint8_t attempts = 0; 105 | uint8_t MAX_ATTEMPTS = 10; 106 | 107 | while (putWriteStart(size) != SUCCESS || putWriteEnd(data, size) != SUCCESS) 108 | { 109 | attempts++; 110 | if (attempts == MAX_ATTEMPTS) 111 | return ERROR_FTPPUT11; 112 | } 113 | 114 | return result; 115 | } 116 | 117 | Result FTP::putWriteStart(unsigned int size) 118 | { 119 | Result result = SUCCESS; 120 | 121 | char buffer[22]; 122 | char resp[11]; 123 | 124 | sprintf_P(buffer, AT_FTPPUT2, size); 125 | strcpy_P(resp, AT_FTPPUT2_RESP); 126 | if (sendCmdAndWaitForResp(buffer, resp, 2000) == FALSE) 127 | return ERROR_FTPPUT2; 128 | 129 | return result; 130 | } 131 | 132 | Result FTP::putWriteEnd(const char *data, unsigned int size) 133 | { 134 | Result result = SUCCESS; 135 | char resp[4]; 136 | 137 | write(data, size); 138 | 139 | strcpy_P(resp, AT_FTPPUT1_RESP); 140 | if (waitForResp(resp, 2000) == FALSE) 141 | return ERROR_FTPPUT11; 142 | 143 | return result; 144 | } 145 | 146 | Result FTP::putEnd() 147 | { 148 | Result result; 149 | 150 | if (sendCmdAndWaitForResp_P(AT_FTPPUT20, AT_FTPPUT20_RESP, 2000) == FALSE) 151 | return ERROR_FTPPUT20; 152 | 153 | result = closeGPRSContext(this); 154 | 155 | return result; 156 | } 157 | -------------------------------------------------------------------------------- /src/Ftp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Ftp.h 3 | * FTP library for the SIM800L board 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #ifndef __FTP_H__ 29 | #define __FTP_H__ 30 | 31 | #include "Sim800.h" 32 | #include "Result.h" 33 | 34 | 35 | class FTP : public SIM800 36 | { 37 | 38 | public: 39 | FTP(unsigned int baudRate, 40 | unsigned int rxPin, 41 | unsigned int txPin, 42 | unsigned int rstPin) : SIM800(baudRate, rxPin, txPin, rstPin){}; 43 | 44 | Result putBegin(const char *apn, 45 | const char *fileName, 46 | const char *server, 47 | const char *usr, 48 | const char *pass, 49 | const char *path = "/"); 50 | Result putWrite(const char *data, unsigned int size); 51 | Result putEnd(); 52 | 53 | private: 54 | Result putWriteStart(unsigned int size); 55 | Result putWriteEnd(const char *data, unsigned int size); 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/GPRS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GPRS.cpp 3 | * GPRS module that implements the basic AT sequences to interact with GPRS 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include "GPRS.h" 29 | #include 30 | 31 | const char BEARER_PROFILE_GPRS[] PROGMEM = "AT+SAPBR=3,1,\"Contype\",\"GPRS\"\r\n"; 32 | const char BEARER_PROFILE_APN[] PROGMEM = "AT+SAPBR=3,1,\"APN\",\"%s\"\r\n"; 33 | const char QUERY_BEARER[] PROGMEM = "AT+SAPBR=2,1\r\n"; 34 | const char OPEN_GPRS_CONTEXT[] PROGMEM = "AT+SAPBR=1,1\r\n"; 35 | const char CLOSE_GPRS_CONTEXT[] PROGMEM = "AT+SAPBR=0,1\r\n"; 36 | 37 | const char SIGNAL_QUALITY[] PROGMEM = "AT+CSQ\r\n"; 38 | const char READ_VOLTAGE[] PROGMEM = "AT+CBC\r\n"; 39 | const char REGISTRATION_STATUS[] PROGMEM = "AT+CREG?\r\n"; 40 | 41 | const char CONNECTED[] PROGMEM = "+CREG: 0,1"; 42 | const char ROAMING[] PROGMEM = "+CREG: 0,5"; 43 | const char BEARER_OPEN[] PROGMEM = "+SAPBR: 1,1"; 44 | const char AT_OK[] PROGMEM = "OK"; 45 | const char AT_OK_[] = "OK"; 46 | 47 | Result openGPRSContext(SIM800 *sim800, const char *apn) 48 | { 49 | Result result = SUCCESS; 50 | uint8_t attempts = 0; 51 | uint8_t MAX_ATTEMPTS = 10; 52 | 53 | sim800->sendATTest(); 54 | 55 | while ((sim800->sendCmdAndWaitForResp_P(REGISTRATION_STATUS, CONNECTED, 12000) != TRUE && 56 | sim800->sendCmdAndWaitForResp_P(REGISTRATION_STATUS, ROAMING, 12000) != TRUE) && 57 | attempts < MAX_ATTEMPTS) 58 | { 59 | sim800->sendCmdAndWaitForResp_P(READ_VOLTAGE, AT_OK, 2000); 60 | sim800->sendCmdAndWaitForResp_P(SIGNAL_QUALITY, AT_OK, 2000); 61 | attempts++; 62 | delay(1000 * attempts); 63 | if (attempts == MAX_ATTEMPTS) 64 | { 65 | sim800->preInit(); 66 | 67 | // Return in order to let the client to decide what to do instead of 68 | // retrying automatically forever 69 | return ERROR_INITIALIZATION; 70 | } 71 | } 72 | 73 | if (sim800->sendCmdAndWaitForResp_P(BEARER_PROFILE_GPRS, AT_OK, 14000) == FALSE) 74 | result = ERROR_BEARER_PROFILE_GPRS; 75 | 76 | char httpApn[64]; 77 | char tmp[24]; 78 | strcpy_P(tmp, apn); 79 | sprintf_P(httpApn, BEARER_PROFILE_APN, tmp); 80 | if (sim800->sendCmdAndWaitForResp(httpApn, AT_OK_, 10000) == FALSE) 81 | result = ERROR_BEARER_PROFILE_APN; 82 | 83 | while (sim800->sendCmdAndWaitForResp_P(QUERY_BEARER, BEARER_OPEN, 10000) == FALSE && attempts < MAX_ATTEMPTS) 84 | { 85 | attempts++; 86 | if (sim800->sendCmdAndWaitForResp_P(OPEN_GPRS_CONTEXT, AT_OK, 10000) == FALSE) 87 | { 88 | result = ERROR_OPEN_GPRS_CONTEXT; 89 | } 90 | else 91 | { 92 | result = SUCCESS; 93 | } 94 | } 95 | 96 | return result; 97 | } 98 | 99 | Result closeGPRSContext(SIM800 *sim800) 100 | { 101 | Result result = SUCCESS; 102 | 103 | if (sim800->sendCmdAndWaitForResp_P(CLOSE_GPRS_CONTEXT, AT_OK, 4000) == FALSE) 104 | result = ERROR_CLOSE_GPRS_CONTEXT; 105 | 106 | return result; 107 | } 108 | -------------------------------------------------------------------------------- /src/GPRS.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GPRS.h 3 | * GPRS module that implements the basic AT sequences to interact with GPRS 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #ifndef __GPRS_H__ 29 | #define __GPRS_H__ 30 | 31 | #include "Result.h" 32 | #include "Sim800.h" 33 | 34 | Result openGPRSContext(SIM800 *sim800, const char *apn); 35 | Result closeGPRSContext(SIM800 *sim800); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/Geo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Geo.cpp 3 | * Geo library for the SIM800L board 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include "Geo.h" 29 | #include "Parser.h" 30 | 31 | #define READ_GPS "AT+CIPGSMLOC=1,1\r\n" 32 | 33 | void Geo::readGpsLocation(char *gps) 34 | { 35 | char buffer[80]; 36 | cleanBuffer(buffer, sizeof(buffer)); 37 | cleanBuffer(gps, sizeof(gps)); 38 | 39 | sendCmd(READ_GPS); 40 | 41 | if (readBuffer(buffer, sizeof(buffer)) == TRUE) 42 | { 43 | parseATResponse(buffer, 19, 4, gps); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Geo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Geo.h 3 | * A Geolocalization library for the SIM800L board 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #ifndef __GEO_H__ 29 | #define __GEO_H__ 30 | 31 | #include "Sim800.h" 32 | 33 | class Geo : public SIM800 34 | { 35 | 36 | public: 37 | Geo(unsigned int baudRate, 38 | unsigned int rxPin, 39 | unsigned int txPin, 40 | unsigned int rstPin) : SIM800(baudRate, rxPin, txPin, rstPin){}; 41 | void readGpsLocation(char *gps); 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/Http.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Http.cpp 3 | * A HTTP library for the SIM800L board 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include "Http.h" 29 | #include "Parser.h" 30 | #include "GPRS.h" 31 | 32 | const char HTTP_INIT[] PROGMEM = "AT+HTTPINIT\r\n"; 33 | const char HTTP_CID[] PROGMEM = "AT+HTTPPARA=\"CID\",1\r\n"; 34 | const char HTTP_PARA[] PROGMEM = "AT+HTTPPARA=\"URL\",\"%s\"\r\n"; 35 | const char HTTP_GET[] PROGMEM = "AT+HTTPACTION=0\r\n"; 36 | const char HTTP_POST[] PROGMEM = "AT+HTTPACTION=1\n"; 37 | const char HTTP_DATA[] PROGMEM = "AT+HTTPDATA=%d,%d\r\n"; 38 | const char HTTP_READ[] PROGMEM = "AT+HTTPREAD\r\n"; 39 | const char HTTP_CLOSE[] PROGMEM = "AT+HTTPTERM\r\n"; 40 | const char HTTP_CONTENT[] PROGMEM = "AT+HTTPPARA=\"CONTENT\",\"application/json\"\r\n"; 41 | const char HTTPS_ENABLE[] PROGMEM = "AT+HTTPSSL=1\r\n"; 42 | const char HTTPS_DISABLE[] PROGMEM = "AT+HTTPSSL=0\r\n"; 43 | const char NORMAL_MODE[] PROGMEM = "AT+CFUN=1,1\r\n"; 44 | const char SIGNAL_QUALITY[] PROGMEM = "AT+CSQ\r\n"; 45 | const char READ_VOLTAGE[] PROGMEM = "AT+CBC\r\n"; 46 | 47 | const char AT_OK[] PROGMEM = "OK"; 48 | const char AT_OK_[] = "OK"; 49 | const char DOWNLOAD[] PROGMEM = "DOWNLOAD"; 50 | const char HTTP_2XX[] PROGMEM = ",2XX,"; 51 | const char HTTPS_PREFIX[] PROGMEM = "https://"; 52 | 53 | 54 | Result HTTP::connect(const char *apn) 55 | { 56 | Result result = openGPRSContext(this, apn); 57 | 58 | if (sendCmdAndWaitForResp_P(HTTP_INIT, AT_OK, 8000) == FALSE) 59 | result = ERROR_HTTP_INIT; 60 | 61 | return result; 62 | } 63 | 64 | Result HTTP::disconnect() 65 | { 66 | Result result = closeGPRSContext(this); 67 | 68 | if (sendCmdAndWaitForResp_P(HTTP_CLOSE, AT_OK, 5000) == FALSE) 69 | result = ERROR_HTTP_CLOSE; 70 | 71 | return result; 72 | } 73 | 74 | Result HTTP::post(const char *uri, const char *body, char *response) 75 | { 76 | Result result; 77 | setHTTPSession(uri); 78 | 79 | char buffer[32]; 80 | char resp[16]; 81 | 82 | unsigned int delayToDownload = 10000; 83 | sprintf_P(buffer, HTTP_DATA, strlen(body), delayToDownload); 84 | strcpy_P(resp, DOWNLOAD); 85 | 86 | sendCmdAndWaitForResp(buffer, resp, 7000); 87 | 88 | purgeSerial(); 89 | sendCmd(body); 90 | 91 | if (sendCmdAndWaitForResp_P(HTTP_POST, HTTP_2XX, delayToDownload) == TRUE) 92 | { 93 | strcpy_P(buffer, HTTP_READ); 94 | sendCmd(buffer); 95 | readResponse(response); 96 | result = SUCCESS; 97 | } 98 | else 99 | { 100 | result = ERROR_HTTP_POST; 101 | } 102 | 103 | return result; 104 | } 105 | 106 | Result HTTP::get(const char *uri, char *response) 107 | { 108 | Result result; 109 | setHTTPSession(uri); 110 | 111 | if (sendCmdAndWaitForResp_P(HTTP_GET, HTTP_2XX, 7000) == TRUE) 112 | { 113 | char buffer[16]; 114 | strcpy_P(buffer, HTTP_READ); 115 | sendCmd(buffer); 116 | result = SUCCESS; 117 | readResponse(response); 118 | } 119 | else 120 | { 121 | result = ERROR_HTTP_GET; 122 | } 123 | 124 | return result; 125 | } 126 | 127 | unsigned int HTTP::readVoltage() 128 | { 129 | char buffer[32]; 130 | char voltage[8]; 131 | cleanBuffer(buffer, sizeof(buffer)); 132 | cleanBuffer(voltage, sizeof(voltage)); 133 | 134 | strcpy_P(buffer, READ_VOLTAGE); 135 | sendCmd(buffer, 500); 136 | 137 | if (readBuffer(buffer, sizeof(buffer)) == TRUE) 138 | { 139 | parseATResponse(buffer, 4, 7, voltage); 140 | } 141 | return atoi(voltage); 142 | } 143 | 144 | unsigned int HTTP::readVoltagePercentage() 145 | { 146 | char buffer[32]; 147 | char voltage[8]; 148 | cleanBuffer(buffer, sizeof(buffer)); 149 | cleanBuffer(voltage, sizeof(voltage)); 150 | 151 | strcpy_P(buffer, READ_VOLTAGE); 152 | sendCmd(buffer); 153 | 154 | if (readBuffer(buffer, sizeof(buffer)) == TRUE) 155 | { 156 | parseATResponse(buffer, 2, 4, voltage); 157 | } 158 | return atoi(voltage); 159 | } 160 | 161 | unsigned int HTTP::readSignalStrength() 162 | { 163 | char buffer[32]; 164 | char signals[8]; 165 | cleanBuffer(buffer, sizeof(buffer)); 166 | cleanBuffer(signals, sizeof(signals)); 167 | 168 | strcpy_P(buffer, SIGNAL_QUALITY); 169 | sendCmd(buffer); 170 | if (readBuffer(buffer, sizeof(buffer)) == TRUE) 171 | { 172 | parseATResponse(buffer, 2, 2, signals); 173 | } 174 | return atoi(signals); 175 | } 176 | 177 | Result HTTP::setHTTPSession(const char *uri) 178 | { 179 | Result result = SUCCESS; 180 | char buffer[128]; 181 | 182 | if (sendCmdAndWaitForResp_P(HTTP_CID, AT_OK, 2000) == FALSE) 183 | result = ERROR_HTTP_CID; 184 | 185 | sprintf_P(buffer, HTTP_PARA, uri); 186 | if (sendCmdAndWaitForResp(buffer, AT_OK_, 2000) == FALSE) 187 | result = ERROR_HTTP_PARA; 188 | 189 | bool https = strncmp_P(uri, HTTPS_PREFIX, strlen_P(HTTPS_PREFIX)) == 0; 190 | if (sendCmdAndWaitForResp_P(https ? HTTPS_ENABLE : HTTPS_DISABLE, AT_OK, 2000) == FALSE) 191 | { 192 | result = https ? ERROR_HTTPS_ENABLE : ERROR_HTTPS_DISABLE; 193 | } 194 | 195 | if (sendCmdAndWaitForResp_P(HTTP_CONTENT, AT_OK, 2000) == FALSE) 196 | result = ERROR_HTTP_CONTENT; 197 | 198 | return result; 199 | } 200 | 201 | void HTTP::readResponse(char *response) 202 | { 203 | char buffer[128]; 204 | cleanBuffer(buffer, sizeof(buffer)); 205 | cleanBuffer(response, sizeof(response)); 206 | 207 | if (readBuffer(buffer, sizeof(buffer)) == TRUE) 208 | { 209 | parseJSONResponse(buffer, sizeof(buffer), response); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/Http.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Http.h 3 | * HTTP library for the SIM800L board 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #ifndef __HTTP_H__ 29 | #define __HTTP_H__ 30 | 31 | #include "Sim800.h" 32 | #include "Result.h" 33 | 34 | class HTTP : public SIM800 35 | { 36 | 37 | public: 38 | HTTP(unsigned int baudRate, 39 | unsigned int rxPin, 40 | unsigned int txPin, 41 | unsigned int rstPin) : SIM800(baudRate, rxPin, txPin, rstPin){}; 42 | Result connect(const char *apn); 43 | Result disconnect(); 44 | Result get(const char *uri, char *response); 45 | Result post(const char *uri, const char *body, char *response); 46 | unsigned int readVoltage(); 47 | unsigned int readVoltagePercentage(); 48 | unsigned int readSignalStrength(); 49 | 50 | private: 51 | void readResponse(char *response); 52 | Result setHTTPSession(const char *uri); 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/Parser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Parser.cpp 3 | * Parser module to deal with parsing 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include "Parser.h" 29 | #include 30 | 31 | void parseATResponse(const char *buffer, unsigned int size, unsigned int offset, char *response) 32 | { 33 | const char *twoPointsPointer = strchr(buffer, ':'); 34 | unsigned int twoPointsIndex = (int)(twoPointsPointer - buffer); 35 | unsigned int valueStartIndex = twoPointsIndex + offset; 36 | for (unsigned int i = valueStartIndex; i < valueStartIndex + size; ++i) 37 | { 38 | response[i - valueStartIndex] = buffer[i]; 39 | response[i - valueStartIndex + 1] = '\0'; 40 | } 41 | } 42 | 43 | void parseJSONResponse(const char *buffer, unsigned int bufferSize, char *response) 44 | { 45 | unsigned int start_index = 0; 46 | unsigned int i = 0; 47 | while (i < bufferSize - 1 && start_index == 0) 48 | { 49 | char c = buffer[i]; 50 | if ('{' == c) 51 | { 52 | start_index = i; 53 | } 54 | ++i; 55 | } 56 | 57 | unsigned int end_index = 0; 58 | int j = bufferSize - 1; 59 | while (j >= 0 && end_index == 0) 60 | { 61 | char c = buffer[j]; 62 | if ('}' == c) 63 | { 64 | end_index = j; 65 | } 66 | --j; 67 | } 68 | 69 | for (int k = 0; k < (end_index - start_index) + 2; ++k) 70 | { 71 | response[k] = buffer[start_index + k]; 72 | response[k + 1] = '\0'; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Parser.h 3 | * Parser module to deal with parsing 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #ifndef __PARSER_H__ 29 | #define __PARSER_H__ 30 | 31 | void parseATResponse(const char *buffer, unsigned int size, unsigned int offset, char *response); 32 | void parseJSONResponse(const char *buffer, unsigned int bufferSize, char *response); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/Result.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Result.h 3 | * Result codes used by the library 4 | * 5 | * Copyright 2021 Antonio Carrasco 6 | * 7 | * The MIT License (MIT) 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #ifndef __RESULT_H_ 29 | #define __RESULT_H_ 30 | 31 | /* Result codes */ 32 | enum Result 33 | { 34 | SUCCESS = 0, 35 | ERROR_INITIALIZATION = 1, 36 | ERROR_BEARER_PROFILE_GPRS = 2, 37 | ERROR_BEARER_PROFILE_APN = 3, 38 | ERROR_OPEN_GPRS_CONTEXT = 4, 39 | ERROR_QUERY_GPRS_CONTEXT = 5, 40 | ERROR_CLOSE_GPRS_CONTEXT = 6, 41 | ERROR_HTTP_INIT = 7, 42 | ERROR_HTTP_CID = 8, 43 | ERROR_HTTP_PARA = 9, 44 | ERROR_HTTP_GET = 10, 45 | ERROR_HTTP_READ = 11, 46 | ERROR_HTTP_CLOSE = 12, 47 | ERROR_HTTP_POST = 13, 48 | ERROR_HTTP_DATA = 14, 49 | ERROR_HTTP_CONTENT = 15, 50 | ERROR_NORMAL_MODE = 16, 51 | ERROR_LOW_CONSUMPTION_MODE = 17, 52 | ERROR_HTTPS_ENABLE = 18, 53 | ERROR_HTTPS_DISABLE = 19, 54 | ERROR_FTPCID = 20, 55 | ERROR_FTPSERV = 21, 56 | ERROR_FTPUN = 22, 57 | ERROR_FTPPW = 23, 58 | ERROR_FTPPUTNAME = 24, 59 | ERROR_FTPPUTPATH = 25, 60 | ERROR_FTPPUT1 = 26, 61 | ERROR_FTPPUT2 = 27, 62 | ERROR_FTPPUT20 = 28, 63 | ERROR_FTPPUT11 = 29 64 | }; 65 | 66 | #endif -------------------------------------------------------------------------------- /src/Sim800.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Sim800.cpp 3 | * A library for SeeedStudio seeeduino GPRS shield 4 | * 5 | * Original work Copyright (c) 2013 seeed technology inc. [lawliet zou] 6 | * Modified work Copyright 2021 Antonio Carrasco 7 | * 8 | * The MIT License (MIT) 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include "Sim800.h" 30 | // In power down the current is 60uA 31 | const char POWER_DOWN[] PROGMEM = "AT+CPOWD=1\r\n"; 32 | const char SLEEP_MODE_2[] PROGMEM = "AT+CSCLK=2\r\n"; 33 | const char SLEEP_MODE_1[] PROGMEM = "AT+CSCLK=1\r\n"; 34 | const char SLEEP_MODE_0[] PROGMEM = "AT+CSCLK=0\r\n"; 35 | const char AT_OK[] PROGMEM = "OK"; 36 | const char POWER_DOWN_OK[] PROGMEM = "DOWN\r\n"; 37 | const char AT[] PROGMEM = "AT\r\n"; 38 | 39 | int SIM800::preInit(void) 40 | { 41 | pinMode(resetPin, OUTPUT); 42 | 43 | digitalWrite(resetPin, HIGH); 44 | delay(200); 45 | digitalWrite(resetPin, LOW); 46 | delay(2000); 47 | digitalWrite(resetPin, HIGH); 48 | delay(3000); 49 | 50 | purgeSerial(); 51 | serialSIM800.flush(); 52 | 53 | sendATTest(); 54 | 55 | return TRUE; 56 | } 57 | 58 | int SIM800::checkReadable(void) 59 | { 60 | return serialSIM800.available(); 61 | } 62 | 63 | int SIM800::readBuffer(char *buffer, int count, unsigned int timeOut) 64 | { 65 | int i = 0; 66 | unsigned long timerStart = millis(); 67 | while (1) 68 | { 69 | while (serialSIM800.available()) 70 | { 71 | char c = serialSIM800.read(); 72 | buffer[i] = c; 73 | buffer[i + 1] = '\0'; 74 | ++i; 75 | if (i > count - 1) 76 | break; 77 | } 78 | if (i > count - 1) 79 | break; 80 | 81 | unsigned long timerEnd = millis(); 82 | if (timerEnd - timerStart > timeOut) 83 | { 84 | break; 85 | } 86 | } 87 | 88 | while (serialSIM800.available()) 89 | { 90 | serialSIM800.read(); 91 | } 92 | return TRUE; 93 | } 94 | 95 | void SIM800::cleanBuffer(char *buffer, int count) 96 | { 97 | for (int i = 0; i < count; i++) 98 | { 99 | buffer[i] = '\0'; 100 | } 101 | } 102 | 103 | void SIM800::sendCmd(const char *cmd, unsigned int delayBeforeSend) 104 | { 105 | serialSIM800.listen(); 106 | serialSIM800.flush(); 107 | delay(delayBeforeSend); 108 | write(cmd); 109 | serialSIM800.flush(); 110 | } 111 | 112 | int SIM800::sendATTest(void) 113 | { 114 | int ret = sendCmdAndWaitForResp_P(AT, AT_OK, DEFAULT_TIMEOUT); 115 | return ret; 116 | } 117 | 118 | int SIM800::waitForResp(const char *resp, unsigned int timeout) 119 | { 120 | int len = strlen(resp); 121 | int sum = 0; 122 | unsigned long timerStart = millis(); 123 | 124 | while (1) 125 | { 126 | if (serialSIM800.available()) 127 | { 128 | char c = serialSIM800.read(); 129 | 130 | #ifdef DEBUG 131 | Serial.print(c); 132 | #endif 133 | 134 | sum = (c == resp[sum] || resp[sum] == 'X') ? sum + 1 : 0; 135 | if (sum == len) 136 | break; 137 | } 138 | unsigned long timerEnd = millis(); 139 | if (timerEnd - timerStart > timeout) 140 | { 141 | return FALSE; 142 | } 143 | } 144 | 145 | while (serialSIM800.available()) 146 | { 147 | serialSIM800.read(); 148 | } 149 | 150 | return TRUE; 151 | } 152 | 153 | void SIM800::sendEndMark(void) 154 | { 155 | serialSIM800.println((char)26); 156 | } 157 | 158 | int SIM800::sendCmdAndWaitForResp(const char *cmd, const char *resp, unsigned timeout) 159 | { 160 | sendCmd(cmd); 161 | return waitForResp(resp, timeout); 162 | } 163 | 164 | int SIM800::sendCmdAndWaitForResp_P(const char *cmd, const char *resp, unsigned timeout) 165 | { 166 | char cmdBuff[128]; 167 | char respBuff[32]; 168 | strcpy_P(cmdBuff, cmd); 169 | strcpy_P(respBuff, resp); 170 | 171 | return sendCmdAndWaitForResp(cmdBuff, respBuff, timeout); 172 | } 173 | 174 | void SIM800::serialDebug(void) 175 | { 176 | while (1) 177 | { 178 | if (serialSIM800.available()) 179 | { 180 | Serial.write(serialSIM800.read()); 181 | } 182 | if (Serial.available()) 183 | { 184 | serialSIM800.write(Serial.read()); 185 | } 186 | } 187 | } 188 | 189 | void SIM800::purgeSerial() 190 | { 191 | while (serialSIM800.available()) 192 | serialSIM800.read(); 193 | } 194 | 195 | void SIM800::write(const char *data) 196 | { 197 | serialSIM800.listen(); 198 | serialSIM800.write(data); 199 | } 200 | 201 | void SIM800::write(const char *data, unsigned int size) 202 | { 203 | serialSIM800.listen(); 204 | serialSIM800.write(data, size); 205 | } 206 | 207 | int SIM800::sleep(bool force) 208 | { 209 | if (force) 210 | { 211 | return sendCmdAndWaitForResp_P(SLEEP_MODE_1, AT_OK, 2000); 212 | } 213 | else 214 | { 215 | return sendCmdAndWaitForResp_P(SLEEP_MODE_2, AT_OK, 2000); 216 | } 217 | } 218 | 219 | int SIM800::powerDown() 220 | { 221 | return sendCmdAndWaitForResp_P(POWER_DOWN, POWER_DOWN_OK, 2000); 222 | } 223 | 224 | void SIM800::wakeUp() 225 | { 226 | preInit(); 227 | } 228 | -------------------------------------------------------------------------------- /src/Sim800.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Sim800.h 3 | * A library for SeeedStudio seeeduino GPRS shield 4 | * 5 | * Original work Copyright (c) 2013 seeed technology inc. [lawliet zou] 6 | * Modified work Copyright 2021 Antonio Carrasco 7 | * 8 | * The MIT License (MIT) 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #ifndef __SIM800_H__ 30 | #define __SIM800_H__ 31 | 32 | #include 33 | #include 34 | 35 | #define TRUE 1 36 | #define FALSE 0 37 | #define DEFAULT_TIMEOUT 5000 38 | 39 | // Comment or uncomment this to debug the library 40 | // #define DEBUG true 41 | 42 | /** SIM800 class. 43 | * Used for SIM800 communication. attention that SIM800 module communicate with MCU in serial protocol 44 | */ 45 | 46 | class SIM800 47 | { 48 | 49 | public: 50 | /** Create SIM800 Instance 51 | * @param baudRate baud rate of uart communication 52 | * @param rxPin uart receive pin to communicate with SIM800 53 | * @param txPin uart transmit pin to communicate with SIM800 54 | */ 55 | SIM800(unsigned int baudRate, 56 | unsigned int rxPin, 57 | unsigned int txPin, 58 | unsigned int rstPin) : serialSIM800(txPin, rxPin) 59 | { 60 | serialSIM800.begin(baudRate); 61 | resetPin = rstPin; 62 | }; 63 | 64 | /** Power on SIM800 65 | */ 66 | int preInit(void); 67 | 68 | /** Check if SIM800 readable 69 | */ 70 | int checkReadable(void); 71 | 72 | /** read from SIM800 module and save to buffer array 73 | * @param buffer buffer array to save what read from SIM800 module 74 | * @param count the maximal bytes number read from SIM800 module 75 | * @param timeOut time to wait for reading from SIM800 module 76 | * @returns 77 | * TRUE on success 78 | * ERROR on error 79 | */ 80 | int readBuffer(char *buffer, int count, unsigned int timeOut = DEFAULT_TIMEOUT); 81 | 82 | /** clean Buffer 83 | * @param buffer buffer to clean 84 | * @param count number of bytes to clean 85 | */ 86 | void cleanBuffer(char *buffer, int count); 87 | 88 | /** send AT command to SIM800 module 89 | * @param cmd command array which will be send to GPRS module 90 | * @param delayBeforeSend integer indicating the sime to wait before sending a command 91 | */ 92 | void sendCmd(const char *cmd, unsigned int delayBeforeSend = 10); 93 | 94 | /**send "AT" to SIM800 module 95 | */ 96 | int sendATTest(void); 97 | 98 | /**send '0x1A' to SIM800 Module 99 | */ 100 | void sendEndMark(void); 101 | 102 | /** check SIM800 module response before time out 103 | * @param *resp correct response which SIM800 module will return. A 'X' char 104 | * can be used to allow any char matching character, example: 105 | * '200' and '201' matches with '20X' 106 | * @param *timeout waiting seconds till timeout 107 | * @returns 108 | * TRUE on success 109 | * ERROR on error 110 | */ 111 | int waitForResp(const char *resp, unsigned timeout); 112 | 113 | /** send AT command to GPRS module and wait for correct response 114 | * @param *cmd AT command which will be send to GPRS module 115 | * @param *resp correct response which GPRS module will return 116 | * @param *timeout waiting seconds till timeout 117 | * @returns 118 | * TRUE on success 119 | * ERROR on error 120 | */ 121 | int sendCmdAndWaitForResp(const char *cmd, const char *resp, unsigned timeout); 122 | 123 | /** 124 | * The sendCmdAndWaitForResp_P() function is similar to sendCmdAndWaitForResp() 125 | * except that cmd and resp are pointers to a string in program space. 126 | */ 127 | int sendCmdAndWaitForResp_P(const char *cmd, const char *resp, unsigned timeout); 128 | 129 | /** used for serial debug, you can specify tx and rx pin and then communicate with GPRS module with common AT commands 130 | */ 131 | void serialDebug(void); 132 | 133 | void purgeSerial(); 134 | 135 | void write(const char *data); 136 | void write(const char *data, unsigned int size); 137 | 138 | int sleep(bool force = FALSE); 139 | int powerDown(); 140 | void wakeUp(); 141 | 142 | protected: 143 | SoftwareSerial serialSIM800; 144 | unsigned int resetPin; 145 | }; 146 | 147 | #endif 148 | --------------------------------------------------------------------------------