Arduino: AT Commands - Read the last line of the serial output using Serial.read() - c++

I constantly pass AT commands to get GSM Signal Strength
My code copies the entire serial output
Kindly advise how to read the latest serial output (last line)
find the output below, in which i need to assign the output from last line (21,0) to the variable "signal"
My Output:
AT
OK
AT+CREG?
+CREG: 0,1
ok
AT+CSQ
+CSQ: 21,0
My code:
byte gsmDriverPin[3] = {
3,4,5};
char signal[10];
char inChar;
int index;
char inData[200];
void setup()
{
//Init the driver pins for GSM function
for(int i = 0 ; i < 3; i++){
pinMode(gsmDriverPin[i],OUTPUT);
}
digitalWrite(5,HIGH);//Output GSM Timing
delay(1500);
digitalWrite(5,LOW);
digitalWrite(3,LOW);//Enable the GSM mode
digitalWrite(4,HIGH);//Disable the GPS mode
delay(2000);
Serial.begin(9600); //set the baud rate
delay(5000);//call ready
delay(5000);
delay(5000);
start_GSM();
}
void loop()
{
Signal_Strength();
Serial.println("AT+CMGF=1");
delay(1000);
Serial.println("AT+CMGS=\"1234567890\"");//Change the receiver phone number
delay(1000);
Serial.println(signal);
delay(1000);
Serial.write(26);
}
void Signal_Strength(){
Serial.println("AT+CSQ");
delay(2000);
read_String();
strtok(inData, ",");
strcpy(signal,strtok(NULL, ","));
}
void read_String() {
index=0;
while(Serial.available() > 0) // Don't read unless
// there you know there is data
{
if(index < 199) // One less than the size of the array
{
inChar = Serial.read(); // Read a character
inData[index] = inChar; // Store it
index++; // Increment where to write next
inData[index] = '\0'; // Null terminate the string
}
}
}
void start_GSM(){
//Configuracion GPRS Claro Argentina
Serial.println("AT");
delay(2000);
Serial.println("AT+CREG?");
delay(2000);
}

First of all, you must seriously redo your AT command handling to
Read and parse the every single response line given back from the modem until you get a final result code. This applies for every single command line invocation, no exceptions whatsoever. See this answer for more details.
Never ever call delay in any code that handles AT commands. See this answer for more details about the risk of aborting the next command.
Before fixing these fundamental issues you cannot expect any successful behaviour. Parsing AT command responses is not that complicated, have a look at the source code for atinout for an example.

Related

Strange characters after JSON

I have an application that gets the Arduino Nano information and sends it to ESP-01 via UART. The ESP-01 send this to MQTT.
NANO CODE:
#include "DHTesp.h"
#include <ArduinoJson.h>
#include <SoftwareSerial.h>
#define gasSensor A1
#define dhtPin 5
#define rain A2
#define soil A3
#define ldr A4
DHTesp dht;
void setup() {
Serial.begin(115200);
pinMode(gasSensor, INPUT);
pinMode(rain, INPUT);
pinMode(soil, INPUT);
pinMode(ldr, INPUT);
digitalWrite(dhtPin, LOW);
dht.setup(dhtPin, DHTesp::DHT11);
}
void loop() {
delay(dht.getMinimumSamplingPeriod());
float humidity = dht.getHumidity();
float temperature = dht.getTemperature();
DynamicJsonBuffer jBuffer;
JsonObject& measure = jBuffer.createObject();
JsonObject& data = jBuffer.createObject();
measure["gas"] = analogRead(gasSensor);
measure["humidity"] = humidity;
measure["temperature"] = temperature;
measure["heatindex"] = dht.computeHeatIndex(temperature, humidity, false);
measure["rain"] = analogRead(rain);
measure["soil"] = analogRead(soil);
measure["ldr"] = analogRead(ldr);
data["measure"] = measure;
data.printTo(Serial);
}
ESP-01 CODE:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* mqtt_server = "0.0.0.0";
WiFiClient espClient;
PubSubClient client(espClient);
char mystr[100];
void setup() {
Serial.begin(115200);
WiFi.begin("", "");
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.print("Connected to IP: ");
Serial.println(WiFi.localIP());
client.setServer(mqtt_server, 1883);
}
void loop() {
if (client.connect("ESP")) {
Serial.println("STATUS MQTT-ESP: OK");
while (true) {
Serial.readBytes(mystr, 108);
client.publish("esp", mystr);
delay(1000);
}
} else {
Serial.println("STATUS MQTT-ESP: OFF");
}
}
But, I'm getting strange characters into MQTT:
And, at the connection between NANO <-uart-> Computer, the JSON is normal:
Someone could help me?
Thanks.
I am basing this answer on a bit of assumptions as I don't have an Arduino at hand.
You send your data like this:
data.printTo(Serial);
This sends the string holding the formatted JSON data. This does not include the terminating 0 byte.
Then you receive it like this:
char mystr[100];
...
while(true){
Serial.readBytes(mystr, 108);
client.publish("esp", mystr);
delay(1000);
}
This has multiple errors:
You do not care if you got any bytes at all. The method returns the number of bytes but you do not handle the return value at all. If you got 0 bytes within the timeout value, you will just send the previous message again instead of waiting for valid data.
You cannot put 108 bytes into memory location of 100 bytes.
You put an array of char into the publish method that does not contain any termination. How should that method know how many characters are really part of the string?
Try this:
while(true){
size_t num = Serial.readBytes(mystr, sizeof(mystr)-1);
mystr[num] = 0;
client.publish("esp", mystr);
delay(1000);
}
You do not have any protocol that allows you to detect when a message starts or ends. UART communiation is a byte stream without any boundaries for datagrams. You must ensure that you know what belongs to a message and what does not. This also means that you can never know if you have a complete message in your receive bufffer or an incomplete or even more than one message. It's up to you to detect and split messages. Fixing this is a bit more complex. I can only give some hints what you need to do.
a) Detect message boundaries:
You might send some terminator like \n, 0 or similar after each JSON string and scan for this extra byte on receiver side.
Or you can send the length of the string before you send the string.
You could also just check on receiver side when you have a matching pair of {}. This would not require any change on sender side.
b) Collect messages:
Call your read function as long as it takes until you detect the end of a string.
You might need to use intermediate buffer to collect multiple read buffers.
c) Forward messages:
As soon as you detected the end of a message, forward it via publish function.
Then move the remaining content of your collection buffer to the start of that buffer.
If you immediately find the end of another message, repeat that step.
If you don't find any complete message, continue to collect more data until the next message is complete.

WebClient and MotionDetector stops after a while

I've been digging this for around a week and doesn't have any way to solve this one. My Arduino code is working for a while (few times / few days) and then stops all of a sudden. I'm trying to implement a WebClient within the Arduino which sends HTTP GET requests to some other server every time (periodically - every 90 seconds) when a motion had been detected / when motion had stopped.
Below you can find the code. Can anyone assist?
#include <Ethernet2.h>
#include <SPI.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0x73, 0x88 };
IPAddress ip(192,168,20,84);
IPAddress server(192,168,50,93); // Google
IPAddress myDns(8, 8, 8, 8);
EthernetClient client;
//getMovement - sends a GET request when motion is detected
void getMovement() {
client.stop();
if (client.connect(server, 8080)) {
client.println("GET /GetARoomMaven/motion?roomId=1&movement=1");
client.println();
Serial.println("Movement Request Sent");
} else {
Serial.println("connection failed");
}
}
//getNoMovement - sends a GET request when motion had stopped
void getNoMovement() {
client.stop();
if (client.connect(server, 8080)) {
client.println("GET /GetARoomMaven/motion?roomId=1&movement=0");
client.println();
Serial.println("Movement Request Sent");
} else {
Serial.println("connection failed");
}
}
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 10;
//the time when the sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 90000;
//
boolean lockLow = true;
boolean takeLowTime;
int pirPin = 2; //the digital pin connected to the PIR sensor's output
int ledPin = 13;
/////////////////////////////
//SETUP
void setup(){
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(pirPin, LOW);
Ethernet.begin(mac);
//give the sensor some time to calibrate
Serial.print("calibrating sensor ");
for(int i = 0; i < calibrationTime; i++){
Serial.print(".");
delay(1000);
}
Serial.println(" done");
Serial.println("SENSOR ACTIVE");
delay(50);
loop();
}
////////////////////////////
//LOOP
void loop(){
if(digitalRead(pirPin) == HIGH){
digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
if(lockLow){
//makes sure we wait for a transition to LOW before any further output is made:
lockLow = false;
Serial.print("motion detected at ");
Serial.print(millis()/1000);
Serial.println(" sec");
getMovement();
}
takeLowTime = true;
}
if(digitalRead(pirPin) == LOW){
digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
//if the sensor is low for more than the given pause,
//we assume that no more motion is going to happen
if(!lockLow && millis() - lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
Serial.print("motion ended at "); //output
Serial.print((millis() - pause)/1000);
Serial.println(" sec");
getNoMovement();
}
}
}
It's hard to say without a better description of symptoms.
Are the LED still blinking ?
If yes, the socket code seems wrong to me:
void getMovement() {
client.stop();
You must remember that TCP requires connection tracking, so you can't immediately stop a socket, it has to linger a bit for acknowledging packets sent.
If you look at the implementation:
void EthernetClient::stop() {
if (_sock == MAX_SOCK_NUM)
return;
[...]
}
stop() will fail if you have more than MAX_SOCK_NUM (which is 4 on your platform) opened at a time. Can this happen?
In all case, you should avoid as much as possible dynamic allocations, you should have a single function sendMovement(bool detected) that's writing the detected value (getMovement and getNoMovement are the same function, so factorize them). You should re-use the client as much as possible (avoid closing the socket and re-opening it unless you get an error from any socket function). Finally, you might want to set up an interrupt on the digital input pin (with some software debouncing) to avoid polling on it, that would release CPU, and, depending on the configuration, might release more time to process SPI messages.
If the LED are not blinking, try to comment out the SPI related code (EthernetClient's code) and check if it works (in that case, I would check the HW for errors, some of the socket code is busy looping (socket::send does this) that would never finish and stop your loop function from progressing. In that case, if you use JTAG to pause the CPU, it'll be in the client.connect or client.println method.
If it still does not work (LED not blinking with no SPI code), then the issue is likely hardware, check voltage / temperature / JTAG connect to the board to interrupt the CPU to figure out where it's struck.
BTW, if you are doing HTTP, the request is wrong and should be:
GET url HTTP/1.1\r\n
Host: yourserverhost.com\r\n
Connection: Keep-Alive\r\n
\r\n
The part HTTP/1.x after the GET url is absolutely required even for HTTP/1.0. Unless you've written your own server (in that case, there's no need to mimick HTTP), it should not work at all, not even once.

Serial.read() skips over serial input

Trying to send serial messages using Arduino Uno and standard IDE. Ran into issue parsing the serial message sent to the device.
See that if I include this line Serial.println("Serial.available() = " + String(Serial.available())); I will be able to read the rest of the message. If this is commented out I will only see the first letter of the message and skip over the rest. Attached image of output that I'm seeing with and without the added line of code.
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial) {} // wait for serial to be initialized
Serial.println("Setup called. Serial port ready.");
Serial.println("Waiting for time sync message...");
while (!Serial.available()) {}
processSyncMessage();
}
void processSyncMessage() {
// parse first letter of message
char messageHeader = (char) Serial.read();
switch (messageHeader) {
case TIME_HEADER:
// do processing
break;
default:
Serial.println("Unknown message sent with header: " + String(messageHeader));
// must include this line in order to see the entire message sent
// just calling a println or a Serial.available() doesn't work ????
Serial.println("Serial.available() = " + String(Serial.available()));
Serial.println("---start of message");
for (int r = 0; r != -1; r = Serial.read()) {
Serial.print((char) r);
}
Serial.println();
Serial.println("---end of message");
break;
}
}
Missing Buffer
With printout
Is this somehow related to a buffer? Can I flush it somehow with fflush(SOME_SECRET_BUFFER)?
have you tried Serial.readString() to parse the entire missing characters?
Serial data is transmitted and received one character at a time. At 9600 baud, the transmission rate is approximately one character per millisecond.
The code assumes that once the first character has arrived, all of them have. This is not the case. The addition of the println consumes CPU time, and therefore has the effect of adding a delay. This delay allows the rest of the original message to be received.
A receive function with an appropriate timeout for your application is needed here.

Recieved String to useable variable in Arduino

I'm trying to use data sent via Bluetooth from a mobile app to the Arduino. There will be 2 strings received dependent on the function required.
First function: When the string "ledon" or "ledoff" received turn on or turn off an led.
Second Function: from the app I get the data a user has typed into 2 boxes, one a text box the other a password box, this is received by the Arduino as one string with comma's as a delimiter so the string can be separated into it's component parts, which in this case are an "ssid name" and a "network key". These details I will be intending to write to an onboard sd card so that the wifi module will be able to logon to the network that the ssid and network key are relevant too.
So far I can get the led light to do as it should, I can also get the string read, separated by the delimiter and printed out to the serial monitor. However when I try to combine the two codes the led function fails to turn on or off the led light although the correct command is printed into the serial monitor. I have researched how to solve this trying each requirement as a standalone function and calling them in the loop section, which individually they work but when called together again the led fails to come on.
This is the code i'm presently using:
const int ledPin = 11;
String readString;
void setup() {
Serial.begin(9600);
pinMode (ledPin, OUTPUT);
}
void loop() {
while (Serial.available()) {
delay(3);
char c = Serial.read();
readString += c;
}
//turns led on or off
if (readString.length() >0) {
Serial.println(readString);
if (readString == "ledon")
{
digitalWrite (ledPin, HIGH);
}
if (readString == "ledoff")
{
digitalWrite (ledPin, LOW);
}
readString="";
//seperates the string into 2 lines using the delimiter ","
String first = Serial.readStringUntil(',');
Serial.read(); //next character is comma, so skip it using this
String second = Serial.readStringUntil(',');
Serial.read();
Serial.println(first);
Serial.println(second);
readString="";
}
}
If I comment out the string part of the code the led turns on and off fine, if I try and run the code as is the code prints everything you would expect but the led doesn't come on.
I'm pretty new to Arduino,c and c++ and I cannot seem to figure this out so any help would be great.
The app I'm using to control this is being built in Mit's App Inventor 2
I have finally resolved this.
I decided to look at other logical steps to find a solution.
I considered the issue could be having different strings that did different things which may be conflicting in some way.
In my research I found reference to the fact that the Bluetooth module HC-05 has 2 pins that in my case were not being utilised, the key pin and the state pin, in this stack overflow discussion Tell when Bluetooth module connects on Arduino and decided this logic of using the "State pin" to signify Bluetooth connection would negate the possibility of any conflicts within the String logic.
Once I had figured out the best way to place and order the "where" statements I managed to get the functionality at this point in my project which then allows me to move on to the next step in the development.
The code I have now arrived at:
const int ledPin1 = 11;
const int ledPin2 = 4;
String readString;
boolean BTconnected = false;
void setup() {
Serial.begin(9600);
pinMode (ledPin1, OUTPUT);
pinMode (ledPin2, INPUT);
}
void loop() {
while (!BTconnected)
{
if ( digitalRead(ledPin2)==HIGH) { BTconnected = true;};
}
digitalWrite(ledPin1, HIGH);
Serial.println("HC-05 is now connected");
Serial.println("");
while (BTconnected)
{
if ( digitalRead(ledPin2)==LOW) { BTconnected = false;
digitalWrite(ledPin1, LOW);
Serial.println("HC-05 is now disconnected");
Serial.println("");
};
while (Serial.available())
{
delay(3);
char c = Serial.read();
readString += c;
}
if (readString.length() >0) {
//Serial.println(readString);
//readString="";
String first = Serial.readStringUntil(',');
Serial.read(); //next character is comma, so skip it using this
Serial.println(first);
//readString="";
String second = Serial.readStringUntil(',');
Serial.read();
Serial.println(second);
Serial.println("");
//readString="";
}
}
}

Using SD.remove() and SD library in Arduino

I'm building a program which takes 10 measurements of an analog voltage on pin0 and is printing it to a log file. The issue I'm running into comes when I try to ensure that the file is blank. I am using SD.remove() in order to remove a previous logfile. When I do this, the new log file is never actually written to. When I remove the call to SD.remove(), the program works correctly. Is this some known bug in the SD library or is there some sneaky way around this?
The code is below.
#include <SD.h>
#define OUTPUT_PIN 9 //Using SparkFun MP3 shield
#define DEFAULT_OUTPUT 10
#define VOLTAGE_REF (5)
//Reads a voltage on pin0. by default, the reference voltage is set to 5 V, but
//it can be changed by changing VOLTAGE_REF.
void setup() {
Serial.begin(9600);
Serial.println("Program Initialized");
pinMode(DEFAULT_OUTPUT ,OUTPUT); //Needs to be on to use the library
pinMode(0, INPUT);
if (!SD.begin(OUTPUT_PIN)) {
//init error
Serial.println("Error initializing SD card. Reset the Arduino and try again");
return;
}
Serial.println("Card sucessfully initialized");
if (SD.exists("LOGFILE.LOG") {
SD.remove("LOGFILE.LOG"); //We don't want to use the same file <<THIS IS THE BUG?
}
delay(10); //Make sure changes are applied
File logFile = SD.open("ANALOG.LOG", FILE_WRITE); //Create a new one every time
if (!SD.exists("LOGFILE.LOG")) {
Serial.println("There was some error making a new instance of the logfile?");
delay(1000);
SD.open("ANALOG.LOG", FILE_WRITE);
}
int i;
if (logFile) {
for(i=0;i<10;i++) {
int j = 0;
char str[64];
Serial.print("Reading analog sensor value");
for(j=0;j<=i;j++) {
Serial.print(".");
}
Serial.println();
logFile.print("Read #");
logFile.print(i+1);
logFile.print(" : ");
logFile.print(doVoltageRead(0));
unsigned char l = logFile.println(" V");
if (!l)
Serial.println("No data written");
delay(500);
}
Serial.println("Done.");
logFile.close(); //Close the logfile
Serial.println("Data sucessfully written");
}
else {
//Couldn't create file
Serial.println("There was an error creating the logfile");
}
}
void loop() {
//We don't really need to do anything here
}
float doVoltageRead(int pin) {
int voltageRead = analogRead(pin);
double divisor = (voltageRead * 0.00097752);
float finalVoltage =(VOLTAGE_REF * divisor);
Serial.println(finalVoltage);
return finalVoltage;
}
So.. First you see if LOGFILE.LOG exists, if it does you delete ANALOG.LOG. Then you create ANALOG.LOG. After that you check if LOGFILE.LOG exists. If it doesn't, you print an error and open ANALOG.LOG.
What exactly is the purpose of LOGFILE.LOG? Shouldn't you just change LOGFILE to ANALOG?
I have found the source of the error. When I called if(SD.exists()) after opening a new logfile, the library didn't like that. I am assuming SD.exists() just checks if the address or object returned by open is NULL. However, calling it when the file is already open would cause some strange behaviors. After removing that call inside open, all is well. Thanks for all the suggestions!