arduino and esp8266 - how to get AT command response into variable - arduino

So i have my arduino and esp8266 wifi module. Everything is connected correctly and sending data to arduino lets me control connection via AT commands.
My skletch looks like this:
void setup()
{
Serial.begin(9600);
Serial1.begin(9600);
}
void loop()
{
if (Serial.available() > 0) {
char ch = Serial.read();
Serial1.print(ch);
}
if (Serial1.available() > 0) {
char ch = Serial1.read();
Serial.print(ch);
}
The code above lets me send commands and see response from esp. In spite of different response time and different answers I need to store response in variable when wifi module such a response creates. Unfortunatelly I cant do this because of Serial1.read() grabing only one char from Serial1.available() buffer instead of full buffer.
I tried approach like this:
if (Serial1.available() > 0) {
while (Serial1.available() > 0) {
char ch = Serial1.read();
Serial.print(ch);
response = response.concat(ch);
}
} else {
String response = "";
}
So as long ther eis something in a buffer it is sent to response variable that concatens last char with itself. And later it can be searched via indefOf command for "OK" marker or "ERROR". But that doesnt work as intended :( It for example may print my variable 8 times (dont know why).
I need full response from wifi module to analaze it for example to make the led on in my arduino board if proper command comes from wifi network, but also send some data if i press button on arduino to the network. Any ideas would be appreciated.
Kalreg.

Try this rather:
String response = ""; // No need to recreate the String each time no data is available
char ch; // No need to recreate the variable in a loop
while (Serial1.available() > 0) {
ch = Serial1.read();
response = response.concat(ch);
}
// Now do whatever you want with the string by first checking if it is empty or not. Then do something with it
Also remember to clear the buffer before you send a command like I suggested in your previous question: how to get AT response from ESP8266 connected to arduino

Related

How to program own Wifi "Mute" Stomp Box to remote control a Behringer X32 Rack?

I´m totally new to coding, this is even my first post here. Im tryng this because nobody sells what I want/need ;-).
I achived already quite a bit, but at this moment I´m getting lost with a lot of things (I read a lot about coding in general and in special with Arduino the last 8 dayas)... but let me explain first what my intention on this project is:
I want to build a "Stomp Box" to mute a Behringer X32 Rack (wireless) Channels/Mutegroups/Buses, just Mute On/Off.. nothing else.
This Box should have 4-6 "stompers" (buttons), each of this buttons should have a different Mute function.
Also the current state of the Channel/Mutegroup/Bus should be indicated by LED´s green if unmuted or red if muted.
Therfore the box needs to evaulate the current state of the designated Channel/Mutegroup/Bus, because it could change also from other remote devices.
And then switch to the opposite state when pressing/stomping on designated button.
I´d like to have code where I can easily change the action of a button, Like:
button1 = /ch/01/mix/on ,i 1
button2 = /config/mute/1 ,i 1
button3 = /dca/1/on ,i 1
so in case I need a differnt Channel/Mutegroup/Bus for another event simply edit and recode my ESP32 Node Kit
So here is my code I already have:
#include "WiFi.h"
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <SPI.h>
#include <OSCMessage.h> //https://github.com/CNMAT/OSC
#define WIFI_NETWORK "xxxxxxxxxx" //SSID of you Wifi
#define WIFI_PASSWORD "xxxxxxxxxxx" //Your Wifi Password
#define WIFI_TIMEOUT_MS 20000 // 20 second WiFi connection timeout
#define WIFI_RECOVER_TIME_MS 30000 // Wait 30 seconds after a failed connection attempt
int muteOn = 0;// 0=Mute
int muteOff = 1;// 1=Unmute
int input;
WiFiUDP Udp;
const IPAddress outIp (192, 168, 10, 129); //Mixers IP
const unsigned int outPort = 10023; //X32 Port
//variables for blinking an LED with Millis
const int led = 2; // ESP32 Pin to which onboard LED is connected
unsigned long previousMillis = 0; // will store last time LED was updated
const long interval = 300; // interval at which to blink (milliseconds)
int ledState = LOW; // ledState used to set the LED
void connectToWiFi(){
Serial.print("Zu WLAN verbinden...");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_NETWORK, WIFI_PASSWORD);
unsigned long startAttemptTime = millis();
while(WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS){
Serial.println(".");
delay(100);
}
if(WiFi.status() != WL_CONNECTED){
Serial.println("Nicht Verbunden!");
//optional take action
}else{
Serial.print("WLAN Verbunden mit ");
Serial.println(WIFI_NETWORK);
Serial.println(WiFi.localIP( ));
}
}
void setup() {
Serial.begin(115200);
connectToWiFi();
Udp.begin(8888);
pinMode(led, OUTPUT);
// Port defaults to 3232
// ArduinoOTA.setPort(3232);
// Hostname defaults to esp3232-[MAC]
// ArduinoOTA.setHostname("myesp32");
// No authentication by default
// ArduinoOTA.setPassword("admin");
// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop(){
ArduinoOTA.handle();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
ledState = not(ledState);
// set the LED with the ledState of the variable:
digitalWrite(led, ledState);
}
input=Serial.read();
if (input=='0'){
// welcher status hat der kanal?
// wenn Kanal gemutet dann unmute und umgekehrt
Serial.println("Mute!");
delay(100);
sendMute(); //send Mute to Mixer
Serial.println("...");
}
if (input=='1'){
Serial.println("UnMute!");
delay(100);
sendUnMute();
Serial.println("...");
}
}
void sendMute() {
//the message wants an OSC address as first argument
OSCMessage msg("/ch/01/mix/on");
msg.add(muteOn);
Udp.beginPacket(outIp, outPort);
msg.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
delay(20);
}
void sendUnMute() {
//the message wants an OSC address as first argument
OSCMessage msg("/ch/01/mix/on");
msg.add(muteOff);
Udp.beginPacket(outIp, outPort);
msg.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
delay(20);
}
So I testet this via serial Monitor, when I input "0" and click send, the mixer mutes channel 1 and on input "1" channel 1 becomes unmuted, so far so good... (OSCMessage msg("/ch/01/mix/on"); ... section.
What bothers me here in special is, I had to hardcode the command "/ch/01/mix/on", because I am not able to declare a variable? for this string? I am already so confused that I don´t know if I even have the terms right :-(
BTW: There are a lot solutions out there how to do it with MIDI, but MIDI is not wireles and I think for my project overkill. I also did some some research on github.com/CNMAT/OSC but I don´t get it... (crying)...
I found also a post here, but this didn´t helped either... :-(
Any advice on that how I can reach my goal?--
Any help is much apprceiated... even in German (my native language... )
PS: Yes I´m a begginner and I admit it. But at least I managed how to connect and flash this thing even via OTA in the last 8 days, so please be easy on me.
Not wanting to hardcode your commands is a good instinct.
The Arduino language is C++, which is (mostly) a superset of C. C and C++ use a preprocessor which lets you define constants and test for their presence.
For instance, you could write:
#define CHAN01_MIX_ON_COMMAND "/ch/01/mix/on"
and then use CHAN01_MIX_ON_COMMAND anywhere you want to use that constant, like so:
void sendMute() {
//the message wants an OSC address as first argument
OSCMessage msg(CHAN01_MIX_ON_COMMAND);
Then if you ever need to change the string "/ch/01/mix/on" you can just change it in one location and not worry about finding every instance of it in your code.
Writing the names in #define statements is a convention people usually follow in order to make it more clear that they're constants.
You have to write the #define line before you use the constant you defined, so putting it at the start of the file (after any #include lines and before your first function) is a good practice. Or if you have several you might put them all in their own file called something like commands.h (the .h means header file)and then include that at the start of any file that needs it like so:
#include "commands.h"
This #include statement would insert the contents of the file commands.h into the file that the statement is in.
When you have several #define statements, keeping them all together in one place (whether it's at the top of the file or in their own file) is also a good practice so that you have one central place to find them and update them if you need to.
Some people will assign the string constant to a variable like so:
char *channel01_mix_on_cmd = "/ch/01/mix/on";
Here char means "a character" - like one letter or number or symbol. The * means pointer to, which lets you use an array of characters. Simple strings in C and C++ are just arrays of characters (or a pointer to the first character), with a special hidden character at the end set to numeric value 0 (not the character '0'). C++ also has a string datatype called std::string and Arduino programs have String but those are both overkill here. They all let you work with strings; String is much easier to use than char * but both have strengths and weaknesses.
Like the #define, you'd also place that outside a function near the start of the file. It defines a global variable that would be available to any function that references it.
You'd also use the variable anywhere they want the string. It's the same idea as using #define, just done slightly differently. For instance:
void sendMute() {
//the message wants an OSC address as first argument
OSCMessage msg(channel01_mix_on_cmd);
Using a variable here is an attempt to save storage by not having multiple copies of the string. It's not necessary; C/C++ compilers have for a very long time detected this and stored only one copy of the string. It might save space if your code is split into multiple files.
Saving space on CPUs like the ESP32 and ESP8266 is important because they have so little memory. #define is fine here because the compiler does it automatically for you.
You can create the command string with sprintf.
so for example:
#define CHANNELON "on"
#define CHANNELOFF "off"
int channel;
int mute;
char messageString[100];
// some code that calculates the channel number and the mute state:
channel = 1;
mute = 1;
// then check the mute state and create the command string:
if (mute)
{
// to turn off a channel:
sprintf(messageString,"/ch/%02d/mix/%s",channel,CHANNELOFF);
}
else
{
// to turn on a channel:
sprintf(messageString,"/ch/%02d/mix/%s",channel,CHANNELON);
}
// send the command:
OSCMessage msg(messageString);
the %02d will substitute an integer with a zero in front,
if it's smaller than 10 and that is always 2 characters long.
so if channel is 1, the result would be 01

Arduino - sending large amount of data over Serial

I am trying to build a simple FLASH memory programmer (for 39SF020A) using my arduino mega. I wrote the C code and Python script to send the data over (And it all works as expected).
I need to transfer about 32k of hexadecimal data, but with my settings only 10k of data took about 4 minutes (115200 BAUD), which i found unnecessary long. Currently, i am sending over serial (from Python) my value with a terminator (i chose '$'), so for exmple '3F$'. adresses are calulated on the arduino, so no need to send them.
In my arduino code, i have
String received_string = Serial.readStringUntil('$');
and after programming every byte to teh FLASH using arduino, it sends back a '\n' to let the Python know, that it is ready to receive next byte (the python is waiting for receiving a 'line' and then continues). I am not really sure if this is a way to do it, if sending only one byte at the time is good idea and if not, how many and how do i parse them on the arduino? Is the feedback loop useful?
Thanks.
Python Code:
('file' contains all data)
for item in file[1:]:
ser.write((item + "$").encode("ascii"))
line = ser.readline()
i += 1
if i >= top:
break
elif (i % 100) == 0:
print(i)
Arduino code (just part of it)
if (Serial.available() > 0){
String received_string = Serial.readStringUntil('$');
programData(received_string.toInt(),program_adress);
program_adress++;
}
void programData(char data_in, unsigned long adress)
{
digitalWrite(OE,HIGH);
digitalWrite(CE,LOW);
writeByte(0xAA, 0x5555);
writeByte(0x55, 0x2AAA);
writeByte(0xA0, 0x5555);
writeByte(data_in, adress);
Serial.print("\n"); // Feedback for Python
delayMicroseconds(30); // Just to be on the safe side
}
void writeByte(char data_in, unsigned long adress)
{
setDataAs(OUTPUT);
digitalWrite(OE,HIGH);
digitalWrite(WE,HIGH);
setAdress(adress);
setData(data_in);
digitalWrite(WE,LOW);
delayMicroseconds(1);
digitalWrite(WE,HIGH);
}
// Sets data BUS to input or output
void setDataAs(char dir){
for (unsigned int i = 0; i < data_size ;i++) pinMode(data[i],dir);
}
// Sets data to specific values
void setData(char data_i){
setDataAs(OUTPUT);
for (int i = 0; i < data_size;i++) { digitalWrite(data[i],bitRead(data_i,i)); }
}
void setAdress(long adr){
// Set all adresses
for (int i = 0; i < adresses_size;i++)
digitalWrite(adresses[i],bitRead(adr,i));
}

MQTT receiving sensor data from different topics but coming across in one payload

Presently I have 2 sensor readings arriving as one payload from 2 topics( or it looks that way), what would be the recommended way to split this one payload into 2 variables(temp, humidity);
The sensor readings are from different topics.
I have tried all manner of ways a person with little experience would try from for loops to try and write half the data to the serial monitor but to no avail.
I tried to enter the topic into this function but it would not compile.
void messageReceived(MQTTClient*client, char topic[], char payload[], int payload_length) {
for (byte i=0;i<6;i++){
Serial.print(payload[i]);
}
}
the output on the serial monitor would be
23.4555.33
if I put a println after the for loop I get
23.45
55.33
Should I have 2 void messageReceived? one for temp and the other for humidity?
say
messageReceivedtemp()
messageReceivedHum()
You are not receiving a single message, you are receiving separate 2 messages.
You have 2 problems with your code.
First you are not checking the topic that the message is arriving on, so you do not know which value is which.
You are just passing the values directly to the serial port without checking the length. You are using a fixed value of 6, but you should be using the payload_length value.
The code should read something like this:
void messageReceived(MQTTClient*client, char topic[], char payload[], int payload_length) {
if (strcmp(topic, "temp") == 0) {
//message arrived on the 'temp' topic
Serial.print("temp: ");
} else if (strcmp(topic, "hum") == 0 {
//message arrived on the 'hum' topic
Serial.print("hum: ");
}
for (int i=0;i<payload_length;i++){
Serial.print(payload[i]);
}
Serial.println();
}

SD card image transfer using xbee

I trying to read SD card image from arduino (20KB - JPEG -using SD library) and transfer through Xbee (series 2) Due to limitation on xbee, have to break to 60 bytes and send until the complete file send. I think, the image stored in ASCII character.
void setup() {
Serial.begin(115200);
if (!SD.begin()) {
Serial.println("begin failed");
return;
}
file = SD.open("PIC00.JPG");
}
void loop() {
Serial.flush();
char buf[64];
if(file) {
while (file.position() < file.size())
{
while (file.read(buf, sizeof(buf)) == sizeof(buf)) // read chunk of 64bytes
{
Serial.write(buf); // Send to xbee via serial
delay(50);
}
}
file.close();
} }
But this method, i can not see complete image transfer at Serial Write. After a while, i came to know the start of image is Y (ascii chracter) and U (end character). I can see only end start character Y can not see the proper end character.
Please advise...trying hard solve this issue. Big Thanks...
The JPEG is actually binary data. To send it, use the version of Serial.write() that includes a length parameter for the number of bytes to send. Otherwise, it thinks you're trying to send a null-terminated string.
(Declare bytesread as a byte at the top of your function.)
while ((bytesread = file.read(buf, sizeof(buf))) > 0)
{
Serial.write(buf, bytesread); // Send to xbee via serial
delay(50);
}
Also note that the delay might not be sufficient -- you should really be using a serial port with hardware flow control (monitoring /CTS from the XBee module) so you know when it's clear to send data to it.

How to capture a variable stream of characters and process them on a Arduino using serial?

I'm trying to read variable streams of characters and process them on the Arduino once a certain string of bytes is read on the Arduino. I have a sample sketch like the following, but I can't figure out how to compare the "readString" to process something on the Arduino. I would like the Arduino to process "commands" such as {blink}, {open_valve}, {close_valve}, etc.
// Serial - read bytes into string variable for string
String readString;
// Arduino serial read - example
int incomingByte;
// flow_A LED
int led = 4;
void setup() {
Serial.begin(2400); // Open serial port and set Baud rate to 2400.
Serial.write("Power on test");
}
void loop() {
while (Serial.available()) {
delay(10);
if (Serial.available() > 0) {
char c = Serial.read(); // Gets one byte from serial buffer
readString += c; // Makes the string readString
}
}
if (readString.length() > 0) {
Serial.println( readString); // See what was received
}
if (readString == '{blink_Flow_A}') {
digitalWrite(led, HIGH); // Turn the LED on (HIGH is the voltage level).
delay(1000); // Wait for one second.
digitalWrite(led, LOW); // Turn the LED off by making the voltage LOW.
delay(1000); // Wait for a second.
}
Some definitions first:
SOP = Start Of Packet (in your case, an opening brace)
EOP = End Of Packet (in your case, a closing brace)
PAYLOAD = the characters between SOP and EOP
PACKET = SOP + PAYLOAD + EOP
Example:
PACKET= {Abc}
SOP = {
EOP = }
PAYLOAD = Abc
Your code should process one character at a time, and should be structured as a state machine.
When the code starts, the parser state is "I'm waiting for the SOP character". While in this state, you throw away every character you receive unless it's equal to SOP.
When you find you received a SOP char, you change the parser state to "I'm receiving the payload". You store every character from now on into a buffer, until you either see an EOP character or exhaust the buffer (more on this in a moment). If you see the EOP char, you "close" the buffer by appending a NULL character (i.e. 0x00) so that it becomes a standard NULL-terminated C-string, and you can work on it with the standard functions (strcmp, strstr, strchr, etc.).
At this point you pass the buffer to a "process()" function, which executes the operation specified by the payload (1)
You have to specify the maximum length of a packet, and size the receive buffer accordingly. You also have to keep track of the current payload length during the "payload receive" state, so you don't accidentally try to store more payload bytes into the temporary buffer than it can hold (otherwise you get memory corruption).
If you fill the receive buffer without seeing an EOP character, then that packet is either malformed (too long) or a transmission error changed the EOP character into something else. In either case you should discard the buffer contents and go back to "Waiting for SOP" state.
Depending on the protocol design, you could send an error code to the PC so the person typing at the terminal or the software on that side knows the last command it sent was invalid or not received correctly.
Finally, the blink code in you snipped should be replaced by non-blocking "blink-without-delay"-style code (look at the example that come with the Arduino IDE).
(1) Example of a "process" function:
void process(char* cmd) {
if (strcmp(cmd, "open_valve") == 0) {
open_valve();
}
else if (strcmp(cmd, "close_valve") == 0) {
close_valve();
}
else {
print_error("Unrecognized command.");
}
}
It seems you are comparing the string in this statement:
if( readString == '{blink_Flow_A}' )
So I don't get your question re :
but I can't figure out how to compare the "readString" to process something
Are you really asking:
How do I extract the commands from an incoming stream of characters?
If that is the case then treat each command as a "packet". The packet is enclosed in brackets: {}. Knowing that the {} brackets are start and end of a packet, it is easy to write a routine to get at the command in the packet.
Once the command is extracted just go through a if-then-else statement to do what each command is supposed to do.
If I totally misunderstood your question I apologize :)
EDIT:
see http://arduino.cc/en/Tutorial/StringComparisonOperators
if( readString == "{blink_Flow_A}" ) should be correct syntax.
Since you have a statement
Serial.println( readString);
you should see the string received.

Resources