I am working with a GSM SIM900 and an Arduino Uno. I am using AT commands for the SIM900. I am successfully getting data from GET requests and showing on the serial monitor, but after the AT+HTTPREAD command I want to store data into a variable. How can I do this? I am getting a JSON Object from the web server and I want to get the Status property from that object and save it into a variable.
#include <SoftwareSerial.h>
SoftwareSerial gprsSerial(2,3);
void setup() {
gprsSerial.begin(9600);
Serial.begin(9600);
Serial.println("Con");
delay(2000);
Serial.println("Done!...");
gprsSerial.flush();
Serial.flush();
// See if the SIM900 is ready
gprsSerial.println("AT");
delay(1000);
toSerial();
// SIM card inserted and unlocked?
gprsSerial.println("AT+CPIN?");
delay(1000);
toSerial();
// Is the SIM card registered?
gprsSerial.println("AT+CREG?");
delay(1000);
toSerial();
// Is GPRS attached?
gprsSerial.println("AT+CGATT?");
delay(1000);
toSerial();
// Check signal strength
gprsSerial.println("AT+CSQ ");
delay(1000);
toSerial();
// Set connection type to GPRS
gprsSerial.println("AT+SAPBR=3,1,\"Contype\",\"GPRS\"");
delay(2000);
toSerial();
// Set the APN
gprsSerial.println("AT+SAPBR=3,1,\"APN\",\"wap.mobilinkworld.com\"");
delay(2000);
toSerial();
// Enable GPRS
gprsSerial.println("AT+SAPBR=1,1");
delay(10000);
toSerial();
// Check to see if connection is correct and get your IP address
gprsSerial.println("AT+SAPBR=2,1");
delay(2000);
toSerial();
}
void loop() {
// initialize http service
gprsSerial.println("AT+HTTPINIT");
delay(2000);
toSerial();
// set http param value
// ToDO : send dynamic value
gprsSerial.println("AT+HTTPPARA=\"URL\",\"http://smockfyp.azurewebsites.net/api/Device/GetStatus?did=1\"");
delay(4000);
toSerial();
// set http action type 0 = GET, 1 = POST, 2 = HEAD
gprsSerial.println("AT+HTTPACTION=0");
delay(6000);
toSerial();
// read server response
gprsSerial.println("AT+HTTPREAD");
delay(1000);
toSerial();
gprsSerial.println("AT+HTTPTERM");
toSerial();
delay(300);
gprsSerial.println("");
delay(10000);
}
void toSerial() {
while(gprsSerial.available()!=0) {
Serial.write(gprsSerial.read());
}
}
This is piece of output I want to store in a variable:
AT+HTTPINIT
OK
AT+HTTPPARA="URL","http://smockfyp.azurewebsites.net/api/DeviceAT+HTTPACTION=0
OK
+HTTPACTION: 0,200,17
AT+HTTPREAD
+HTTPREAD: 17
[{"Status":true}]
OK
Start by acquiring a large A3 sheet of paper, find a red pen and write 1000 times
I will never use delay as a substitute for reading and parsing responses from a modem.
I will never use delay as a substitute for reading and parsing responses from a modem.
I will never use delay as a substitute for reading and parsing responses from a modem.
I will never use delay as a substitute for reading and parsing responses from a modem.
I will never use delay as a substitute for reading and parsing responses from a modem.
...
Then read this answer, following the instructions regarding V.250. And when you have properly digested all information from the answer (it probably takes some time to let all sink in), then follow the link to another answer in the comment below it (which contains information to capture response content).
Of course the first part was meant to be funny, but I am dead serious about the rest; you have some huge AT command knowledge "holes" you must fill. You will not be able to get any information out until you do. It should not be very difficult, but it will require some effort.
First you should initialize a char array named a for storing the value and also declare a variable int flag=0;.
Then modify your toSerial() function as follows:
void toSerial() {
while(gprsSerial.available()!=0) {
if( gprsSerial.read() == '[' )
flag=2;
else if(flag == 2 && gprsSerial.read() == ':')
while(gprsSerial.read() != '}') {
a[i]= gprsSerial.read();
i++;
}
else if(flag == 0)
Serial.write(gprsSerial.read());
else
flag--;
}
}
Related
I am trying to control a LED from Thingspeak server by using the GSM module.
The data received is successfully being printed on serial monitor(which is '1' as last updated) but when I am trying to assign that data to a variable so as to control the inbuilt LED of Arduino, nothing happens.
#include <SoftwareSerial.h>
SoftwareSerial SIM900A(10, 11);
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
SIM900A.begin(9600);
Serial.begin(9600);
while (!Serial)
;
Serial.println("Arduino is ready");
SIM900A.begin(9600);
Serial.println("SIM900A started at 9600");
delay(1000);
Serial.println("Setup Complete");
}
void loop()
{
SIM900A.println("AT");
delay(1000);
ShowSerialData();
SIM900A.println("AT+CIPSHUT");
delay(2000);
ShowSerialData();
SIM900A.println("AT+CIPMUX=0");
delay(2000);
ShowSerialData();
SIM900A.println("AT+CGATT=1");
delay(5000);
SIM900A.println("AT+CSTT=\"INTERNET\",\"\",\"\"");
delay(4000);
SIM900A.println("AT+CIICR");
delay(3000);
ShowSerialData();
SIM900A.println("AT+CIFSR");
delay(5000);
ShowSerialData();
SIM900A.println("AT+CIPSTART=\"TCP\",\"184.106.153.149\",\"80\"");
delay(4000);
ShowSerialData();
SIM900A.println("AT+CIPSEND");
delay(4000);
SIM900A.print("GET /channels/798173/fields/1/last");
SIM900A.print("\r\n\x1A");
ShowSerialData();
char led = SIM900A.read();
Serial.print(led);
if (led == '1')
{
digitalWrite(LED_BUILTIN, HIGH);
}
else if (led == '0')
{
digitalWrite(LED_BUILTIN, LOW);
}
delay(8000);
}
void ShowSerialData()
{
while (SIM900A.available() != 0)
Serial.print(char(SIM900A.read()));
}
Last portion of the output from the serial monitor:
CONNECT OK
AT+CIPSEND
> ⸮GET /channels/798173/fields/1/last
SEND OK
1
As pointed out by #Saurabh P Bhandari, you cannot read the same data from the serial twice, thus you'd need to read the data in a variable in the first place if you wish to use it.
String getSerialData(){
String buffer="";
while (SIM900A.available() ){
char c = SIM900A.read();
buffer+=c;
}
return buffer;
}
Then you can use String led = getSerialData() to populate led with the buffer.
Here, you need to beware that the function getSerialData would return anything present on the buffer and would look something like:
GET /channels/798173/fields/1/last
SEND
HTTP RESPONSE
It appears that you're only interested in HTTP RESPONSE, thus you can update your conditionals to be
if(led.endsWith("1"))
...
else if(led.endsWith("0"))
From what I have understood so far, in this snippet
SIM900A.print("GET /channels/798173/fields/1/last");
SIM900A.print("\r\n\x1A");
ShowSerialData();
ShowSerialData() is printing the output which is '1'. Then immediately your are reading data into the variable led. Since, the actual data received is being printed already from ShowSerialData(), the next time you call SIM900A.read() will return either nothing or next set of data being sent by your module.
You are likely getting rate limited because you are hitting ThingSpeak servers too frequently. You can only update a channel once every 15s with a free account. Obviously, it makes no sense to ask for a value faster than it can be updated, i.e., once every 15s with a free account.
Consider putting some required delays in your code to ensure your device is not blacklisted for abuse of terms.
I've been trying to get the BME680 to work and for the most part it seems to be working great. I do have one issue and that is with the gas sensor.
I write all the contents of the BME680 out to a webpage and all of the other values remain consistent.
Temperature: 77.29 *F
Humidity: 59.12 %
Pressure: 1010.45 millibars
Air Quality: 3.24 KOhms
On every refresh of the page the values for Temperature, Humidity, and Pressure all remain close to their values. They correct for a little while and show the minor fluctuations correctly. When it starts to rain the pressure goes down, the humidity goes up, etc... The issue is the Gas Sensor. On ever refresh the value keeps increasing. Regardless of whether I refresh it once per minute or per hour it keeps increasing. I'm clearly doing something wrong.
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#include <WiFi101.h>
#include <WiFiUdp.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0; // your network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS;
WiFiServer server(80);
#define SEALEVELPRESSURE_HPA (1023.03)
Adafruit_BME680 bme; // I2C
void setup() {
//Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT); // set the LED pin mode
bme.begin();
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
//Serial.println("WiFi shield not present");
while (true); // don't continue
}
// attempt to connect to WiFi network:
while ( status != WL_CONNECTED) {
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
server.begin(); // start the web server on port 80
}
void loop() {
WiFiClient client = server.available(); // listen for incoming clients
if (client) { // if you get a client,
//Serial.println("new client"); // print a message out the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
//Serial.write(c); // print it out the serial monitor
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
if (! bme.performReading()) {
client.print("Failed to perform reading :(<br>");
return;
}
// the current weather condidtions
client.print("Temperature: ");
client.print((bme.temperature * 9/5) + 32);
client.print(" *F<br>");
client.print("Humidity: ");
client.print(bme.humidity);
client.print(" %<br>");
client.print("Pressure: ");
client.print(bme.pressure / 100.0);
client.print(" millibars<br>");
client.print("Air Quality: ");
client.print(bme.gas_resistance / 1000.0);
client.print(" KOhms<br>");
delay(2000);
// The HTTP response ends with another blank line:
client.println();
// break out of the while loop:
break;
}
else { // if you got a newline, then clear currentLine:
currentLine = "";
}
}
else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// close the connection:
client.stop();
//Serial.println("client disonnected");
}
}
I see two important points. Two for the beginning. Missing the ambient temperature and the sea-level.
Default ambient is: 25deg.C
Default sea-level is: 500 meter
Add this with correct values to your code. Then you have todo some automatic calibrations after burn in time. My own experience is that 2 weeks 24/7 is needed to get the sensor much old as needed. Next step look in the BOSCH original library and example code. Then start over again. Currently i'm rewriting the driver for the BME and BMP series for Tasmota (github). Lot's of work believe me. And i'm from the physics and chemical side. So some research helps always.
I am trying to send sensor data to a MySQL server of mine but can't achieve that. I followed several similar examples here in other questions but it isn't working. The Arduino code is given below. The idea is to measure the voltage and current across a load and send it to a MySQL server. TIA.
#include <SoftwareSerial.h>
SoftwareSerial gprsSerial(7, 8);
//variables that imitates actual voltage and current data
float a=random(300.0);
float b=random(2.00);
char c[10]="B110";
void setup() {
gprsSerial.begin(19200);
Serial.begin(19200);
Serial.println("Config SIM900A...");
delay(2000);`enter code here`
Serial.println("Done!...");
gprsSerial.flush();
Serial.flush();
// attach or detach from GPRS service
gprsSerial.println("AT+CGATT?");
delay(100);
toSerial();
// bearer settings
gprsSerial.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
delay(2000);
toSerial();
// bearer settings
gprsSerial.println("AT+SAPBR=3,1,\"APN\",\"my carrier apn here\"");
delay(2000);
toSerial();
// bearer settings
gprsSerial.println("AT+SAPBR=1,1");
delay(2000);
toSerial();
}
void loop() {
// initialize http service
gprsSerial.println("AT+HTTPINIT");
delay(2000);
toSerial();
// set http param value
gprsSerial.println("AT+HTTPPARA=\"URL\",\"http://mocdl.net/api/data/create?voltage="" + a + ""¤t="" + b + "" &load_id="" + c + ""\"");
delay(2000);
toSerial();
// set http action type 0 = GET, 1 = POST, 2 = HEAD
gprsSerial.println("AT+HTTPACTION=0");
delay(6000);
toSerial();
// read server response
gprsSerial.println("AT+HTTPREAD");
delay(1000);
toSerial();
gprsSerial.println("");
gprsSerial.println("AT+HTTPTERM");
toSerial();
delay(300);
gprsSerial.println("");
delay(10000);
}
void toSerial() {
while(gprsSerial.available()!=0) {
Serial.write(gprsSerial.read());
}
}
As Panciz said you should set you APN (i think you already know that).
You should also make a small change in your program.
gprsSerial.println("AT+HTTPPARA=\"URL\",\"http://mocdl.net/api/data/create?voltage="" + a + ""¤t="" + b + "" &load_id="" + c + ""\"");
The above line wont work as you expected.
So edit the http request line as follows :
gprsSerial.println("AT+HTTPPARA=\"URL\",\"http://mocdl.net/api/data/create?voltage=%f¤t=%f&load_id=%f\"",a,b,c);
You must set your APN.
For example in my case I need to add
mySerial.println("AT+SAPBR=3,1,\"APN\",\"internet\"")
I use arduino Nano and Sim900 module. I want, when a message is received, Arduino to reply back "thanks" to the sender.
My message receive function code is:
void recieveSms(){
Serial.print("\r");
delay(1000);
Serial.print("AT+CMGF=1\r");
delay(1000);
Serial.print("AT+CSCS=\"GSM\"\r");
delay(1000);
Serial.print("AT+CNMI=2,1\r");// set new message remind
delay(1000);
Serial.print("AT+CMGR=2\r"); // read message at position 2
delay(1000);
Serial.print("AT+CMGD=2\r"); // delete SMS at position 2
delay(1000);
}
that works, but how I can retrieve sender number from the message?
Its easy to use the GSM Library that comes with arduino IDE.
The GSM library is included with Arduino IDE 1.0.4 and later.
Using this libarray use remoteNumber()
Here is the example code on the documentation page
#include <GSM.h>
// PIN Number
#define PINNUMBER ""
// initialize the library instance
GSM gsmAccess; // include a 'true' parameter for debug enabled
GSM_SMS sms;
char remoteNumber[20]; // Holds the emitting number
void setup()
{
// initialize serial communications
Serial.begin(9600);
Serial.println("SMS Messages Receiver");
// connection state
boolean notConnected = true;
// Start GSM shield
// If your SIM has PIN, pass it as a parameter of begin() in quotes
while(notConnected)
{
if(gsmAccess.begin(PINNUMBER)==GSM_READY)
notConnected = false;
else
{
Serial.println("Not connected");
delay(1000);
}
}
Serial.println("GSM initialized");
Serial.println("Waiting for messages");
}
void loop()
{
char c;
// If there are any SMSs available()
if (sms.available())
{
Serial.println("Message received from:");
// Get remote number
sms.remoteNumber(remoteNumber, 20);
Serial.println(remoteNumber);
// This is just an example of message disposal
// Messages starting with # should be discarded
if(sms.peek()=='#')
{
Serial.println("Discarded SMS");
sms.flush();
}
// Read message bytes and print them
while(c=sms.read())
Serial.print(c);
Serial.println("\nEND OF MESSAGE");
// delete message from modem memory
sms.flush();
Serial.println("MESSAGE DELETED");
}
delay(1000);
}
I was trying to upload a Xively feed with an Arduino connected via an Arduino GSM shield.
Xively does not publish any specific example for an Arduino GSM shield. I tried to use the Arduino GSM Pachube Client library changing "pachube.com" in "xively.com", but it did not work. It seems that my GSM shield is able to connect but cannot put the data to the server.
In my example I created a device called "Arduino GSM" with just one channel called "sensor1". In the request log I cannot read any request incoming, although the serial monitor shows that a connection with the server occurs.
This is the code I tried:
// Original GSM Pachube client modified for Xively
// Changes: pachube.com -> xively.com
// inserted APIKEY, FEEDID, USERAGENT
// inserted GPRS_APN, login, password
/*GSM Pachube client
This sketch connects an analog sensor to Pachube (http://www.pachube.com)
using a Telefonica GSM/GPRS shield.
This example has been updated to use version 2.0 of the Pachube.com API.
To make it work, create a feed with a datastream, and give it the ID
sensor1. Or change the code below to match your feed.
Circuit:
* Analog sensor attached to analog in 0
* GSM shield attached to an Arduino
* SIM card with a data plan
created 4 March 2012
by Tom Igoe
and adapted for GSM shield by David Del Peral
This code is in the public domain.
http://arduino.cc/en/Tutorial/GSMExamplesPachubeClient
*/
// libraries
#include <GSM.h>
// Pachube Client data -> changed in Xively Data
#define APIKEY "myapikey" // replace your pachube api key here
#define FEEDID 111111111 // replace your feed ID
#define USERAGENT "Arduino GSM" // user agent is the project name
// PIN Number
#define PINNUMBER ""
// APN data
#define GPRS_APN "WINDBIZ WEB" // replace your GPRS APN
#define GPRS_LOGIN "" // replace with your GPRS login
#define GPRS_PASSWORD "" // replace with your GPRS password
// initialize the library instance:
GSMClient client;
GPRS gprs;
GSM gsmAccess;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
// IPAddress server(216,52,233,121); // numeric IP for api.pachube.com
char server[] = "api.xively.com"; // name address for pachube API
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
boolean lastConnected = false; // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000; //delay between updates to Pachube.com
void setup()
{
// initialize serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
// connection state
boolean notConnected = true;
// After starting the modem with GSM.begin()
// attach the shield to the GPRS network with the APN, login and password
while(notConnected)
{
if((gsmAccess.begin(PINNUMBER)==GSM_READY) &
(gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD)==GPRS_READY))
notConnected = false;
else
{
Serial.println("Not connected");
delay(1000);
}
}
}
void loop()
{
// read the analog sensor:
int sensorReading = analogRead(A0);
// if there's incoming data from the net connection.
// send it out the serial port. This is for debugging
// purposes only:
if (client.available())
{
char c = client.read();
Serial.print(c);
}
// if there's no net connection, but there was one last time
// through the loop, then stop the client:
if (!client.connected() && lastConnected)
{
client.stop();
}
// if you're not connected, and ten seconds have passed since
// your last connection, then connect again and send data:
if(!client.connected() && ((millis() - lastConnectionTime) > postingInterval))
{
sendData(sensorReading);
}
// store the state of the connection for next time through
// the loop:
lastConnected = client.connected();
}
/*
This method makes a HTTP connection to the server.
*/
void sendData(int thisData)
{
// if there's a successful connection:
if (client.connect(server, 80))
{
Serial.println("connecting...");
// send the HTTP PUT request:
client.print("PUT /v2/feeds/");
client.print(FEEDID);
client.println(".csv HTTP/1.1");
client.print("Host: api.xively.com\n");
client.print("X-ApiKey: ");
client.println(APIKEY);
client.print("User-Agent: ");
client.println(USERAGENT);
client.print("Content-Length: ");
// calculate the length of the sensor reading in bytes:
// 8 bytes for "sensor1," + number of digits of the data:
int thisLength = 8 + getLength(thisData);
client.println(thisLength);
// last pieces of the HTTP PUT request:
client.print("Content-Type: text/csv\n");
client.println("Connection: close");
client.println();
// here's the actual content of the PUT request:
client.print("sensor1,");
client.println(thisData);
}
else
{
// if you couldn't make a connection:
Serial.println("connection failed");
Serial.println();
Serial.println("disconnecting.");
client.stop();
}
// note the time that the connection was made or attempted
lastConnectionTime = millis();
}
/*
This method calculates the number of digits in the
sensor reading. Since each digit of the ASCII decimal
representation is a byte, the number of digits equals
the number of bytes.
*/
int getLength(int someValue)
{
// there's at least one byte:
int digits = 1;
// continually divide the value by ten,
// adding one to the digit count for each
// time you divide, until you're at 0:
int dividend = someValue /10;
while (dividend > 0)
{
dividend = dividend /10;
digits++;
}
// return the number of digits:
return digits;
}