"null" at the end of string from file.readStringUntil() - arduino

Im working with esp32s3 feather right now. I need to log some data when there is no WiFi connection. Write works fine for me but when I want to read line with readStringUntil(), i always get "null" at the end of read string. Here is code:
In loop:
if ((millis() - sdLast) > sdTime)
{
for (int i = 0; i < maxSensors; i++)
{
if (activeSensors[i] != "")
{
String requestData = "{\"data\":[{\"name\":\"" + sensorNames[i] + "\" ,\"temp\": \"" + actTemp[i] + "\",\"hum\": \"" + actHum[i] + "\",\"time\": \"" + actTime[i] + "\",\"scanCount\": \"" + scanCount[i] + "\"}]}\n";
appendFile(SD, "/all.txt", requestData.c_str());
sdReady = true;
}
}
sdLast = millis();
}
Function to read from file:
void readLinesSD(fs::FS &fs, const char *path)
{
File file = fs.open(path);
WiFiClient client;
HTTPClient http;
http.begin(client, serverName);
http.addHeader("Content-Type", "application/json");
if (!file)
{
Serial.println("Failed to open file for reading");
return;
}
while (file.available())
{
buffer = file.readStringUntil('\n');
serializeJson(doc, buffer);
Serial.println(buffer);
int httpResponseCode = http.POST(buffer);
Serial.println(httpResponseCode);
doc.clear();
delay(200);
}
http.end();
file.close();
}
Append function:
void appendFile(fs::FS &fs, const char *path, const char *message)
{
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if (!file)
{
Serial.println("Failed to open file for appending");
return;
}
if (file.print(message))
{
Serial.println("Message appended");
}
else
{
Serial.println("Append failed");
}
file.close();
}
SO basically I want to save data to file and then, when the WiFi connection is back I want to send data to database for further presentation. When I read file i got this results:
{"data":[{"name":"P RHT 902631" ,"temp": "19.53","hum": "48","time": "1674746950","scanCount": "4"}]}null
{"data":[{"name":"P RHT 90262A" ,"temp": "19.38","hum": "50","time": "1674746957","scanCount": "4"}]}null
{"data":[{"name":"P RHT 902629" ,"temp": "19.36","hum": "49","time": "1674746958","scanCount": "5"}]}null
I tried using some special characters like "%" at the end of lines and then read line untill this special character but got same problem. When I used the same function on my other esp32 board everything was read fine. Anyone know what might cause this problem? Thanks for any help

I messed up with function to read file. I serialized for no reason. Without it, "null" disapear :)

Related

Error transferring https://speech.googleapis.com/v1/speech:recognize?key=,myKey> - server replied: Bad Request [Problem on Windows OS]

I am using google speech-to-text api to convert my audio file to text. Following is my code(in Qt):
`QString fileName = QDir::currentPath() + "/audio.wav"; //this is my audio file
QFile audioFile(fileName);
if(!audioFile.open(QIODevice::ReadOnly | QIODevice::Text)){
QMessageBox::critical(0,"Error",fileName+" Not found!");
ui->pushButton_4->setText("Speech to text");
return;
}
int idx = ui->comboBox->currentIndex();
QString enc;
if (idx == -1)
enc = "en-US";
else
enc = ui->comboBox->itemData(idx).toString(); //Language selected by user
QByteArray audioData=audioFile.readAll();
QUrl url("https://speech.googleapis.com/v1/speech:recognize");
QUrlQuery query;
query.addQueryItem("key","myKeyHere...");
url.setQuery(query);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader,"audio/x-flac");
QJsonObject json;
QJsonObject config;
config["encoding"]="FLAC";
config["sampleRateHertz"]=44100;
config["languageCode"]=enc;
json["config"]=config;
QJsonObject audio;
audio["content"]=QString::fromLatin1(audioData.toBase64());
json["audio"]=audio;
QByteArray jsonData=QJsonDocument(json).toJson();
QNetworkAccessManager *manager=new QNetworkAccessManager();
QNetworkReply *reply=manager->post(request,jsonData);
QObject::connect(reply,&QNetworkReply::finished,[this,reply](){
if(reply->error()!=QNetworkReply::NoError){
QMessageBox::critical(0,"Error Occured",reply->errorString());
qDebug() << reply->readAll();
ui->pushButton_4->setText("Speech to text");
return;
}
else if(reply->error()==QNetworkReply::UnknownNetworkError){
QMessageBox::warning(0,"Network Error","Please check your internet connection and try again!");
ui->pushButton_4->setText("Speech to text");
}
else if(reply->isFinished() && reply->error()==QNetworkReply::NoError){
QJsonDocument responseJson=QJsonDocument::fromJson(reply->readAll());
QJsonObject object=responseJson.object();
QString ResponseText=object["results"].toArray()[0].toObject()
["alternatives"].toArray()[0].toObject()["transcript"].toString();
QTextCursor cur = curr_browser->textCursor();
qDebug() << "Response Data :" << ResponseText;
cur.insertText(ResponseText);
ui->pushButton_4->setText("Speech to text");
}
reply->deleteLater();
});`
This code is working perfectly on Ubuntu but not on windows. When i run this on Ubunutu, i am receiving the response, but on windows i receive the following error:
Error transferring https://speech.googleapis.com/v1/speech:recognize?key=,myKey> - server replied: Bad Request
Following is the code to record an audio file:
`if (m_audioRecorder->state() == QMediaRecorder::StoppedState) {
QString fileName = QDir::currentPath() + "/audio.wav";
m_audioRecorder->setOutputLocation(QUrl::fromLocalFile(fileName));
qDebug()<<"Recording your audio!!";
ui->pushButton_4->setText("Stop ?");
QAudioEncoderSettings settings;
settings.setCodec("audio/x-flac");
settings.setSampleRate(0);
settings.setBitRate(0);
settings.setChannelCount(1);
settings.setQuality(QMultimedia::EncodingQuality(2));
settings.setEncodingMode(QMultimedia::ConstantQualityEncoding);
m_audioRecorder->setEncodingSettings(settings, QVideoEncoderSettings(), "");
m_audioRecorder->record();
}
else {
qDebug()<<"stopped your recording!";
ui->pushButton_4->setText("Processing ...");
m_audioRecorder->stop();
speechToTextCall(); //calling the code to send request to google api
}`
Can anyone help please?
I tried changing the encodig and container type, but nothing worked on Windows.
I have found the solution of above problem. Windows does not recognize the auido/x-flac encoding so i modified my encoding code as follows:
'
#ifdef Q_OS_WIN
settings.setCodec("audio/pcm");
#else
settings.setCodec("audio/x-flac");
#endif
'
I made the same changes at other two places where encoding was set and it worked on windows as well.

How to load config and save new config LittleFS ESP32?

I'm using a json file in the data folder. I want to use this as a config file and update it with values as needed. I have a simple sketch to store ssid and password. First read it out, then change it, then read it out again via the serial monitor for testing.
The problem is the first read seems to already have been overwritten, even if i call the overwrite function much later, I have tested this with different delays between the first read and the overwrite function.
It seems pretty straight forward to do, so why does it show the overwritten value before the function is called?
Here is the code:
readJSON(LITTLEFS, "/config.json");
String test = config["ssid"];
Serial.println(test);
delay(10);
String test2;
config["ssid"] = "InternetName";
serializeJson(config, test2);
writeFile(LITTLEFS, "/config.json", test2.c_str()); // String to Const char*
delay(10);
readJSON(LITTLEFS, "/config.json");
String test3 = config["ssid"];
Serial.println(test3);
Here are readJSON and writeFile functions:
DynamicJsonDocument config(1024);
void readJSON(fs::FS &fs, const char * path){
Serial.printf("Reading Json: %s\r\n", path);
String output;
File file = fs.open(path);
if(!file || file.isDirectory()){
Serial.println("- failed to open file for reading");
return;
}
Serial.println("- read from file:");
while(file.available()){
//Serial.write(file.read());
char intRead = file.read();
output += intRead;
}
deserializeJson(config, output);
file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\r\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("- failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("- file written");
} else {
Serial.println("- write failed");
}
file.close();
}
config.json:
{
"ssid": "nameofinternet",
"password": "password"
}
Output:
Reading Json: /config.json
- read from file:
InternetName
Writing file: /config.json
- file written
Reading Json: /config.json
- read from file:
InternetName

How to use char* with SD library with Arduino?

I am writing a data logger and would like to keep the files limited to a specific number of entries. I am trying to write this bit of code in the setup, so that when the Arduino powers on, it will write to a new file just to keep things simple. However, when I try to open the file I can't, although I am not sure why. Can anyone offer any explanation?
char *fileName; //global name
File logFile; //global file
//everything else is in setup()
char * topPart = "/Data/Data"; //first part of every file
char * lowerPart = ".txt"; // jus the extention
char * itter; //used to hold the char of i later
fileName = "/Data/Data.txt"; //start with the first file possible.
for(int i=0; i<=100;i++) {
if(!SD.exists(fileName)) {
Serial.print("opening file: ");
Serial.print(fileName);
logFile = SD.open(fileName, FILE_WRITE);
if(logFile) {
logFile.println("I made it");
Serial.println("in the file");
}
if(!logFile) {
Serial.println("somthing bad");
}
break;
} else {
itter = (char *)(i+48);
strcpy(fileName,topPart);
strcpy(fileName,itter);
strcpy(fileName,lowerPart);
Serial.println(i);
}
}
Lots of problems.
the construction of itter is wrong.
strcpy doesn't append just cpy.
Here is a code example to build your filename. This a basic C program. Remove the #include and main for Arduino, this allows to test on your computer whether the program is ok.
#include <string.h>
#define TOPPART "/Data/Data"
#define LOWERPART ".txt"
int main(void) {
char buf[64];
snprintf(buf, sizeof(buf), "%s%s", TOPPART, LOWERPART);
for (int i = 0; i < 100; i++) {
/* here your stuff to check if the filename froml buf exists*/
snprintf(buf, sizeof(buf), "%s%d%s", TOPPART, i, LOWERPART);
}
return 0;
}

Udp server using Qt, server status reports

I'm trying to make simple Udp communication between two application.
Client sends request to server to start some processing calculations etc. Server response is result of this computations. Server should report about its state.
My code:
onServerRecv method:
void MainWindow::onServerRecv()
{
while(m_udpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(m_udpSocket->pendingDatagramSize());
m_udpSocket->readDatagram(datagram.data(),datagram.size(),&m_sender,
&m_senderPort);
QDateTime dt = QDateTime::currentDateTime();
QString sDtString = dt.toString("yyyy-MM-dd HH:mm:ss");
QString sLog = sDtString + ":" + QString::fromUtf8(datagram) + "\n";
m_textEdit->append(sLog);
//process datagram
instructionCall(datagram,m_sender,m_senderPort);
}
}
instructionCall:
void MainWindow::instructionCall(QByteArray instruction, QHostAddress addr,
qint16 senderPort)
{
if(instruction == "start")
{
QByteArray started = "started";
m_udpSocket->writeDatagram(started,m_sender,m_senderPort);
m_status = "bussy";
connect(&m_timer1,SIGNAL(timeout()),this,SLOT(sendStatus()));
m_timer1.start(500);
for(int i = 0; i != std::numeric_limits<int>::max(); i++)
{
}
m_status = "finished data ready";
disconnect(&m_timer1,SIGNAL(timeout()),this,SLOT(sendStatus()));
QByteArray finished = "finished";
m_udpSocket->writeDatagram(finished,m_sender,m_senderPort);
}
}
sendStatus:
void MainWindow::sendStatus()
{
m_udpSocket->writeDatagram(m_status,m_sender,m_senderPort);
}
I hope that it's clear what I want to do. Any suggestions about solutions? Can it be done without threads?

Unix Client and Server Stuck in an Infinite Loop After Reading a File to the Client

I am currently making a simple client and server but I have run into an issue. Part of the system is for the client to query about a local file on the server. The contents of that file must be then sent to the client. I am able to send all the text within a file to the client however it seems to be stuck in the read loop on the client. Below are the code spits for both the client and server that are meant to deal with this:
Client Code That Reads The Loop
else if(strcmp(commandCopy, get) == 0)
{
char *ptr;
int total = 0;
char *arguments[1024];
char copy[2000];
char * temp;
int rc;
strcpy(copy, command);
ptr = strtok(copy," ");
while (ptr != NULL)
{
temp = (char *)malloc(sizeof(ptr));
temp = ptr;
arguments[total] = temp;
total++;
ptr = strtok (NULL, " ");
}
if(total == 4)
{
if (strcmp(arguments[2], "-f") == 0)
{
printf("1111111111111");
send(sockfd, command, sizeof(command), 0 );
printf("sent %s\n", command);
memset(&command, '\0', sizeof(command));
cc = recv(sockfd, command, 2000, 0);
if (cc == 0)
{
exit(0);
}
}
else
{
printf("Here");
strcpy(command, "a");
send(sockfd, command, sizeof(command), 0 );
printf("sent %s\n", command);
memset(&command, '\0', sizeof(command));
cc = recv(sockfd, command, 2000, 0);
}
}
else
{
send(sockfd, command, sizeof(command), 0 );
printf("sent %s\n", command);
memset(&command, '\0', sizeof(command));
while ((rc = read(sockfd, command, 1000)) > 0)
{
printf("%s", command);
}
if (rc)
perror("read");
}
}
Server Code That Reads the File
char* getRequest(char buf[], int fd)
{
char * ptr;
char results[1000];
int total = 0;
char *arguments[1024];
char data[100];
FILE * pFile;
pFile = fopen("test.txt", "r");
ptr = strtok(buf," ");
while (ptr != NULL)
{
char * temp;
temp = (char *)malloc(sizeof(ptr));
temp = ptr;
arguments[total] = temp;
total++;
ptr = strtok (NULL, " ");
}
if(total < 2)
{
strcpy(results, "Invaild Arguments \n");
return results;
}
if(pFile != NULL)
{
while(fgets(results, sizeof(results), pFile) != NULL)
{
//fputs(mystring, fd);
write(fd,results,strlen(results));
}
}
else
{
printf("Invalid File or Address \n");
}
fclose(pFile);
return "End of File \0";
}
Server Code to execute the command
else if(strcmp(command, "get") == 0)
{
int pid = fork();
if (pid ==-1)
{
printf("Failed To Fork...\n");
return-1;
}
if (pid !=0)
{
wait(NULL);
}
else
{
char* temp;
temp = getRequest(buf, newsockfd);
strcpy(buf, temp);
send(newsockfd, buf, sizeof(buf), 0 );
exit(1);
}
}
The whole else if clause in the client code is a bit large for a function, let alone a part of a function as it presumably is. The logic in the code is ... interesting. Let us dissect the first section:
else if (strcmp(commandCopy, get) == 0)
{
char *ptr;
int total = 0;
char *arguments[1024];
char *temp;
ptr = strtok(copy, " ");
while (ptr != NULL)
{
temp = (char *)malloc(sizeof(ptr));
temp = ptr;
arguments[total] = temp;
total++;
ptr = strtok(NULL, " ");
}
I've removed immaterial declarations and some code. The use of strtok() is fine in context, but the memory allocation is leaky. You allocate enough space for a character pointer, and then copy the pointer from strtok() over the only pointer to the allocated space (thus leaking it). Then the pointer is copied to arguments[total]. The code could, therefore, be simplified to:
else if (strcmp(commandCopy, get) == 0)
{
char *ptr;
int total = 0;
char *arguments[1024];
ptr = strtok(copy, " ");
while (ptr != NULL)
{
arguments[total++] = ptr;
ptr = strtok(NULL, " ");
}
Nominally, there should be a check that you don't overflow the arguments list, but since the original limits the string to 2000 characters, you can't have more than 1000 arguments (all single characters separated by single spaces).
What you have works - it achieves the same assignment the long way around, but it leaks memory prodigiously.
The main problem seems to be that the server sends all the contents, but it doesn't close the socket, so the client has no way of knowing the server's done. If you close the socket after you finish sending the data (or just call shutdown()), then the client's read() will return 0 when it finishes reading the data.
FWIW, there are lots of other problems with this code:
getRequest: you call malloc but never free. In fact, the return value is thrown away.
Why bother forking if you're just going to wait() on the child?
You probably want to use strlcpy instead of strpcy to avoid buffer overruns.

Resources