25#include <SoftwareSerial.h>
27void SIM900::sendCommand(String message) {
28 this->sim900->println(message);
31String SIM900::getResponse() {
34 if(this->sim900->available() > 0) {
35 String response = this->sim900->readString();
44String SIM900::getReturnedMode() {
45 String response = this->getResponse();
46 return response.substring(response.lastIndexOf(
'\n') + 1);
49bool SIM900::isSuccessCommand() {
50 return this->getReturnedMode() == F(
"OK");
53String SIM900::rawQueryOnLine(uint16_t line) {
54 String response = this->getResponse();
57 uint16_t currentLine = 0;
58 for(
int i = 0; i < response.length(); i++)
59 if(currentLine == line && response[i] !=
'\n')
60 result += response[i];
61 else if(response[i] ==
'\n') {
64 if(currentLine > line)
71String SIM900::queryResult() {
72 String response = this->getResponse();
73 String result = F(
"");
75 int idx = response.indexOf(
": ");
77 result = response.substring(
79 response.indexOf(
'\n', idx)
87 this->sim900->begin(9600);
91 this->sendCommand(F(
"AT"));
92 return this->isSuccessCommand();
96 this->sendCommand(F(
"AT+CPIN?"));
97 return this->isSuccessCommand();
104 this->sendCommand(
"AT+CPIN=\"" + String(pin) +
"\"");
105 return this->isSuccessCommand();
111 this->sendCommand(
"AT+CSQ");
113 String response = this->queryResult();
114 uint8_t delim = response.indexOf(
',');
119 signal.rssi = (uint8_t) response.substring(0, delim).toInt();
120 signal.bit_error_rate = (uint8_t) response.substring(delim + 1).toInt();
130 this->sendCommand(
"ATD+ " + number +
";");
132 SIM900DialResult result = SIM900_DIAL_RESULT_ERROR;
133 String mode = this->getReturnedMode();
135 if(mode == F(
"NO DIALTONE"))
136 result = SIM900_DIAL_RESULT_NO_DIALTONE;
137 else if(mode == F(
"BUSY"))
138 result = SIM900_DIAL_RESULT_BUSY;
139 else if(mode == F(
"NO CARRIER"))
140 result = SIM900_DIAL_RESULT_NO_CARRIER;
141 else if(mode == F(
"NO ANSWER"))
142 result = SIM900_DIAL_RESULT_NO_ANSWER;
143 else if(mode == F(
"OK"))
144 result = SIM900_DIAL_RESULT_OK;
150 this->sendCommand(F(
"ATDL"));
152 SIM900DialResult result = SIM900_DIAL_RESULT_ERROR;
153 String mode = this->getReturnedMode();
155 if(mode == F(
"NO DIALTONE"))
156 result = SIM900_DIAL_RESULT_NO_DIALTONE;
157 else if(mode == F(
"BUSY"))
158 result = SIM900_DIAL_RESULT_BUSY;
159 else if(mode == F(
"NO CARRIER"))
160 result = SIM900_DIAL_RESULT_NO_CARRIER;
161 else if(mode == F(
"NO ANSWER"))
162 result = SIM900_DIAL_RESULT_NO_ANSWER;
163 else if(mode == F(
"OK"))
164 result = SIM900_DIAL_RESULT_OK;
170 this->sendCommand(F(
"ATA"));
172 SIM900DialResult result = SIM900_DIAL_RESULT_ERROR;
173 String mode = this->getReturnedMode();
175 if(mode == F(
"NO CARRIER"))
176 result = SIM900_DIAL_RESULT_NO_CARRIER;
177 else if(mode == F(
"OK"))
178 result = SIM900_DIAL_RESULT_OK;
184 this->sendCommand(F(
"ATH"));
185 return this->isSuccessCommand();
191 this->sendCommand(F(
"AT+CMGF=1"));
193 this->sendCommand(
"AT+CMGS=\"" + number +
"\"");
195 this->sendCommand(message);
197 this->sim900->write(0x1a);
199 return this->getReturnedMode().startsWith(
">");
204 simOperator.mode = 0;
205 simOperator.format = 0;
206 simOperator.name =
"";
208 this->sendCommand(F(
"AT+COPS?"));
210 String response = this->queryResult();
211 uint8_t delim1 = response.indexOf(
','),
212 delim2 = response.indexOf(
',', delim1 + 1);
214 simOperator.mode = (uint8_t) response.substring(0, delim1).toInt();
215 simOperator.format = (uint8_t) response.substring(delim1 + 1, delim2).toInt();
216 simOperator.name = response.substring(delim2 + 2, response.length() - 2);
222 this->sendCommand(F(
"AT+CMGF=1"));
223 if(!this->isSuccessCommand())
226 this->sendCommand(F(
"AT+CGATT=1"));
227 if(!this->isSuccessCommand())
231 "AT+CSTT=\"" + apn.apn +
232 "\",\"" + apn.username +
233 "\",\"" + apn.password +
"\""
236 return (this->hasAPN = this->isSuccessCommand());
243 this->sendCommand(F(
"AT+CIICR"));
246 return this->isSuccessCommand();
251 response.status = -1;
257 "AT+CIPSTART=\"TCP\",\"" +
request.domain +
261 String resp = this->getResponse();
265 if(!resp.endsWith(F(
"CONNECT OK")))
268 String requestStr =
request.method +
" " +
269 request.resource +
" HTTP/1.0\r\nHost: " +
272 for(
int i = 0; i <
request.header_count; i++)
273 requestStr +=
request.headers[i].key +
": " +
274 request.headers[i].value +
"\r\n";
277 requestStr +=
request.data +
"\r\n";
279 requestStr += F(
"\r\n");
280 this->sendCommand(requestStr);
288 "AT+CCLK=\"" + String(config.year <= 9 ?
"0" :
"") + String(config.year) +
289 "/" + String(config.month <= 9 ?
"0" :
"") + String(config.month) +
290 "/" + String(config.day <= 9 ?
"0" :
"") + String(config.day) +
291 "," + String(config.hour <= 9 ?
"0" :
"") + String(config.hour) +
292 ":" + String(config.minute <= 9 ?
"0" :
"") + String(config.minute) +
293 ":" + String(config.second <= 9 ?
"0" :
"") + String(config.second) +
294 "+" + String(config.gmt <= 9 ?
"0" :
"") + String(config.gmt) +
"\""
297 return this->isSuccessCommand();
306 this->sendCommand(F(
"AT+CMGF=1"));
307 if(!this->isSuccessCommand())
310 this->sendCommand(F(
"AT+CENG=3"));
311 if(!this->isSuccessCommand())
313 this->sendCommand(F(
"AT+CCLK?"));
315 String time = this->queryResult();
316 time = time.substring(1, time.length() - 2);
318 uint8_t delim1 = time.indexOf(
'/'),
319 delim2 = time.indexOf(
'/', delim1 + 1),
320 delim3 = time.indexOf(
',', delim2),
321 delim4 = time.indexOf(
':', delim3),
322 delim5 = time.indexOf(
':', delim4 + 1),
323 delim6 = time.indexOf(
'+', delim5);
325 rtc.year = (uint8_t) time.substring(0, delim1).toInt();
326 rtc.month = (uint8_t) time.substring(delim1 + 1, delim2).toInt();
327 rtc.day = (uint8_t) time.substring(delim2 + 1, delim3).toInt();
328 rtc.hour = (uint8_t) time.substring(delim3 + 1, delim4).toInt();
329 rtc.minute = (uint8_t) time.substring(delim4 + 1, delim5).toInt();
330 rtc.second = (uint8_t) time.substring(delim5 + 1, delim6).toInt();
331 rtc.gmt = (uint8_t) time.substring(delim6 + 1).toInt();
338 "AT+CPBW=" + String(index) +
339 ",\"" + account.number +
340 "\"," + account.numberType +
341 ",\"" + account.name +
"\""
343 return this->isSuccessCommand();
347 this->sendCommand(
"AT+CPBR=" + String(index));
350 accountInfo.numberType = 0;
352 String response = this->queryResult();
353 response = response.substring(response.indexOf(
',') + 1);
355 uint8_t delim1 = response.indexOf(
','),
356 delim2 = response.indexOf(
',', delim1 + 1);
358 accountInfo.number = response.substring(1, delim1 - 1);
360 uint8_t type = (uint8_t) response.substring(delim1 + 1, delim2).toInt();
361 if(type == 129 || type == 145)
362 accountInfo.numberType = type;
363 else accountInfo.numberType = 0;
365 accountInfo.name = response.substring(delim2 + 2, response.length() - 2);
370 this->sendCommand(
"AT+CPBW=" + String(index));
371 return this->isSuccessCommand();
376 capacity.used = capacity.max = 0;
377 capacity.memoryType = F(
"");
379 this->sendCommand(
"AT+CPBS?");
381 String response = this->queryResult();
382 uint8_t delim1 = response.indexOf(
','),
383 delim2 = response.indexOf(
',', delim1 + 1);
385 capacity.memoryType = response.substring(1, delim1 - 1);
386 capacity.used = (uint8_t) response.substring(delim1 + 1, delim2).toInt();
387 capacity.max = (uint8_t) response.substring(delim2 + 1).toInt();
393 this->sendCommand(F(
"AT+CNUM"));
396 account.name = F(
"");
398 String response = this->queryResult();
399 if(response == F(
""))
402 uint8_t delim1 = response.indexOf(
','),
403 delim2 = response.indexOf(
',', delim1 + 1),
404 delim3 = response.indexOf(
',', delim2 + 1),
405 delim4 = response.indexOf(
',', delim3 + 1);
407 account.name = response.substring(1, delim1 - 1);
408 account.number = response.substring(delim1 + 2, delim2 - 1);
409 account.type = (uint8_t) response.substring(delim2 + 1, delim3).toInt();
410 account.speed = (uint8_t) response.substring(delim3 + 1, delim4).toInt();
411 account.service = (uint8_t) response.substring(delim4 + 1).toInt();
412 account.numberType = 0;
418 this->sendCommand(F(
"AT+GMI"));
419 return this->rawQueryOnLine(2);
423 this->sendCommand(F(
"AT+GMR"));
425 String result = this->rawQueryOnLine(2);
426 result = result.substring(result.lastIndexOf(F(
":")) + 1);
432 this->sendCommand(F(
"AT+GSN"));
433 return this->rawQueryOnLine(2);
437 this->sendCommand(F(
"AT+GMM"));
438 return this->rawQueryOnLine(2);
442 this->sendCommand(F(
"AT+GOI"));
443 return this->rawQueryOnLine(2);
447 this->sendCommand(F(
"AT+CIFSR"));
448 return this->rawQueryOnLine(2);
bool savePhonebook(uint8_t index, SIM900CardAccount account)
Save a contact in the SIM card's phonebook.
String manufacturer()
Get the manufacturer name of the SIM900 module.
SIM900DialResult redialUp()
Redial the last outgoing call.
String chipName()
Get the chip name of the SIM900 module.
SIM900PhonebookCapacity phonebookCapacity()
Get information about the capacity of the SIM card's phonebook.
SIM900DialResult acceptIncomingCall()
Accept an incoming call.
SIM900DialResult dialUp(String number)
Initiate an outgoing call to a phone number.
bool enableGPRS()
Enable the General Packet Radio Service (GPRS) for data communication.
String ipAddress()
Get the IP address assigned to the SIM900 module.
SIM900CardAccount cardNumber()
Get the SIM card number.
String chipModel()
Get the chip model of the SIM900 module.
bool deletePhonebook(uint8_t index)
Delete a contact from the SIM card's phonebook.
SIM900Operator networkOperator()
Get information about the current network operator.
bool sendSMS(String number, String message)
Send an SMS (Short Message Service).
bool updateRtc(SIM900RTC config)
Update the SIM900 module's real-time clock (RTC).
String softwareRelease()
Get the software release version of the SIM900 module.
void close()
Close the communication with the SIM900 module.
bool hangUp()
Hang up an active call.
SIM900(SoftwareSerial *_sim900)
Constructor for the SIM900 class.
bool connectAPN(SIM900APN apn)
Connect to an Access Point Name (APN) for mobile data.
bool changeCardPin(uint8_t pin)
Change the PIN code of the SIM card.
SIM900RTC rtc()
Get the real-time clock (RTC) information.
bool handshake()
Initialize communication with the SIM900 module and perform a handshake.
bool isCardReady()
Check if the SIM card is ready.
String imei()
Get the International Mobile Equipment Identity (IMEI) number of the SIM900 module.
SIM900CardAccount retrievePhonebook(uint8_t index)
Retrieve a contact from the SIM card's phonebook.
SIM900Signal signal()
Get the signal strength and bit error rate of the network connection.
SIM900HTTPResponse request(SIM900HTTPRequest request)
Send an HTTP request to a remote server.
A structure representing Access Point Name (APN) configuration for mobile data.
A structure representing a card account, including name, number, type, and service information.
A structure representing an HTTP request.
A structure representing an HTTP response.
A structure representing mobile network operator information.
A structure representing the capacity of a phonebook memory type.
A structure representing real-time clock (RTC) information.
A structure representing signal strength and bit error rate information.