ESP8266: How to send TCP messages using AT+CIPSEND command - sockets

I am experimenting with Arduino and ESP8266 module, and now I am trying to send some sensor data to a TCP server. For this purposes I am using AT+CIPSTART command (to establish a TCP connection) and AT+CIPSEND to send the data.
If I am testing it using Serial Monitor, it works fine. After entering CIPSEND command I can write some text in a terminal and this message/text will be sent to the TCP server.
When I am trying to make it inside Arduino sketch, then it sends an empty message. The connection works, but I do not see any data.
How can I send a message text (msg) with my TCP packet?
Here is a code snippet
// ESP8266 Client
String cmd = "AT+CIPSTART=\"TCP\",\"";// Setup TCP connection
cmd += IP;
cmd += "\",3103";
sendDebug(cmd);
delay(2000);
if( Serial.find( "Error" ) )
{
debug.print( "RECEIVED: Error\nExit1" );
return;
}
String msg = "test";
Serial.print( "AT+CIPSEND=" );
Serial.println( msg.length() );
if(Serial.find( ">" ) )
{
debug.print(">");
debug.print(msg);
Serial.print(msg);
}
else
{
sendDebug( "AT+CIPCLOSE" );//close TCP connection
}
if( Serial.find("OK") )
{
debug.println( "RECEIVED: OK" );
}
else
{
debug.println( "RECEIVED: Error\nExit2" );
}
}

First of all, Select how much character or byte is needed to transmit. It is better to use softwareSerial library to connect with ESP8266 and send AT commands.
Suppose yow want to send 5 bytes.Type the following AT commands and must give a delay more than 100 millisecond before sending data. Here "\r" is carriage return and "\n" is new line. After including this, ESP8266 can understand you have ended the command.
esp.print("AT+CIPSEND=5\r\n");
delay(1000);
esp.print("Hello");
Your code is not working because you are using unvarnished transmission mode. So to complete a packet you need to transmit 2048 bytes which you are not writing.

Related

Why does Rasp Pi Pico can not connect to TCP Server after some point?

I use Raspberry Pi Pico with ESP8266 WiFi module, and I am trying to write a TCP client. Rasp Pi Pico is able to send AT commands and receive responses and send data through UART. Also the TCP client is able to send data to the TCP server, which runs in my laptop. However the problem is that the client is not able to connect to the server after some point.
Let me first show the server-side code. In server, I am trying to receive data basically. ConnectionResetError was a problem for me so I wrote the following except block. I am not sure it is buggy or not, since I'm kind of a noob in this area.
import socket
HOST = ""
PORT = 8080
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
mysocket.bind((HOST, PORT))
mysocket.listen(1)
while True:
print("Waiting...")
conn, addr = mysocket.accept()
print('[SERVER] - Connected from: %s' % str(addr))
while True:
try:
request = conn.recv(1024)
if not request:
break
conn.sendall(request.upper())
print('[SERVER] - Received Data: %s' % str(request))
except ConnectionResetError as cr_err:
break
conn.close()
print("[SERVER] - Disconnected")
Here is my client-side code. In client, I wrote two helper classes called ESP8266 and Sensor, in which I control the WiFi module and read analog value from a sensor. Pico first tries to start WiFi module, afterwards it tries to connect to TCP server and send data. After some point it does not connect to the TCP server, so it restart the WiFi module and reconnects.
class EndDevice:
def __init__(self, sensor_id):
self.__wifi_module = ESP8266(UART_PIN, BAUDRATE)
self.__sensor = Sensor(sensor_id, SENSOR_PIN)
def start(self):
self.__wifi_module.start()
self.__wifi_module.set_mode(STATION_MODE)
self.__wifi_module.join_access_point(AP_NAME, AP_PWD)
def reconnect(self):
self.__wifi_module.restart()
self.__wifi_module.set_mode(STATION_MODE)
self.__wifi_module.join_access_point(AP_NAME, AP_PWD)
def run(self):
retry_count = 0
while True:
if self.__wifi_module.start_connection("TCP", SERVER_HOST, SERVER_PORT):
self.__wifi_module.send_data(
str(self.__sensor.generate_package()))
self.__wifi_module.close_connection()
else:
retry_count += 1
if retry_count == MAX_RETRY:
break
if __name__ == "__main__":
pico = EndDevice("SM-0")
pico.start()
while True:
pico.run()
pico.reconnect()
Finally I will share some of the methods in classes ESP8266 and UARTHandler (which is used in ESP8266), so you can see if I do anything non-sense.
start_connection method in ESP8266 is as follows. In this method, I tried to send the corresponding AT command to connect to a TCP server. In the method self.__uart_handler.send_receive_cmd timeout duration is 2000ms, and other parameters are AT command, connection_type (TCP), server IP address and server port, in order.
def start_connection(self, conn_type, remote_ip, remote_port):
conn_type, remote_ip = "\"{}\"".format(conn_type), "\"{}\"".format(remote_ip)
response = self.__uart_handler.send_receive_cmd(2000, CONN_START, conn_type, remote_ip, str(remote_port))
if "OK" in response:
self.__log("Connected to {} at port {}.".format(remote_ip, remote_port))
return True
else:
self.__log("Failed to create a connection with {} at port {}.".format(remote_ip, remote_port))
return False
send_receive_cmd method in UARTHandler is as follows. In this method I use lots of helper methods as you can see, however they are just formatting and writing to UART or reading from UART. I also insert a timeout between UART-read and UART-write
def __generate_cmd(self, cmd, *args):
if len(args) != 0:
cmd += "="
for idx, each in enumerate(args):
cmd += str(each)
if idx != len(args)-1:
cmd += ","
cmd += "\r\n"
return cmd
def __send_cmd(self, cmd, *args):
sent_cmd = self.__generate_cmd(cmd, *args)
self.__uart.write(sent_cmd)
def __receive_response(self, cmd):
response = self.__uart.read()
try: return response.decode('utf-8')
except: return response
def send_receive_cmd(self, timeout, cmd, *args):
self.__send_cmd(cmd, *args)
utime.sleep_ms(timeout)
return self.__receive_response(self.__generate_cmd(cmd, *args))
Let me ask my question again. This codes are working properly in starting-restarting and sending data for (let me say) 3 connections. However, after some connect-disconnect later, TCP client is not able to make a connection with TCP server. Again after some failed connection attempt, WiFi module is restarted and TCP connection is made and working properly again.

I need help to get data sent from an instrument via udp protocol

i have an instrument that measures so2 and i have a standard program that makes me see the data, but i need to connect the instrument to a server and send all the data to a database. I used wireshark to see how it comunicate with the software, but i don't understand what method to use to make my program. Here i have the wireshark dump:
the red circle indicates the measure that the instrument made.
P.S. sorry for my bad eng
So i solved my question as i'm about to show:
i made a listener and a caller;
caller:
`from socket import socket, AF_INET, SOCK_DGRAM
SERVER_IP = '192.168.1.99'
PORT_NUMBER = 53700
SIZE = 1024
print ("Test client sending packets to IP {0}, via port {1}\n".format(SERVER_IP, PORT_NUMBER))
mySocket = socket( AF_INET, SOCK_DGRAM )
mySocket.bind(('192.168.1.100', 57806))
while True:
data = bytes.fromhex('014630303430335230303102313103')
mySocket.sendto(data,(SERVER_IP,PORT_NUMBER))
exit()`
listener:
`from socket import socket, gethostbyname, AF_INET, SOCK_DGRAM
import sys
PORT_NUMBER = 57806
SIZE = 1024
hostName = gethostbyname( '' )
mySocket = socket( AF_INET, SOCK_DGRAM )
mySocket.bind( (hostName, PORT_NUMBER) )
print ("Test server listening on port {0}\n".format(PORT_NUMBER))
while True:
(data,addr) = mySocket.recvfrom(SIZE)
print (data)
sys.ext()`
i saw on wireshark that if i sent a request packet copied from the ones that i already have, the instrument would give me back the response; so i setupped a listener on the a choosen port, and now i get all the data!
the highlighted packet is the one i sent from the caller script.

read / write on socket descriptors linux c

I am trying to send the contents of a file from the server to the client , I am reading the file line by line using fgets and writing to the socket descriptor line by line , on the client side , i am in an a while loop , reading the sent contents.I am not being able to terminate the server sending sequence , i.e the client keeps reading the buffer and the next program line is not executed , I think thers something wrong with my way of sending or recieving . here is the code :
server :
filefd = fopen("clients.txt","a+");
while(fgets(filcont,300,filefd) != NULL)
{// write whole file contents to client
n=write(newsockfd,filcont,strlen(filcont));
if(n==0) break;
memset(filcont,'\0',300);
}
fclose(filefd);
client side :
while(n>0){
n = read(sockfd,buffer,sizeof(buffer)-1);
if(n==0) break;
printf("%s\nbytes read :%d \n",buffer,n);
memset(buffer,'\0',256);
}
printf("Enter peer name ( except yours ) to send connection request : \n");
the above line ( printf , peer name doesnot get executed until i terminate the server)
I was able to figure it out , I sent the file contents from the server using fread instead of fgets ( line by line ) and used a single read() at the client . this was the quick fix.
But I also figured out another technique when in case you have to compulsorily use fgets , where the while loop at the client side makes the socket nonblocking for read and then blocking again , the code is pasted below.
flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
while(n>0){
n = read(sockfd,buffer,sizeof(buffer)-1);
if(n==0) break;
if(n==-1) printf("\nNon blocking read failed congrats");
printf("%s\n",buffer);
memset(buffer,'\0',256);
}
printf("\nbytes read :%d \n",n);
val = fcntl(sockfd, F_GETFL, 0);
flags = O_NONBLOCK;
val &= ~flags; // makes it blocking again
fcntl(sockfd,F_SETFL,val);
The code from stackoverflow was refered to make the socket blocking

connect and send on the socket succeeds, even if WIFI not enabled and server is only reacheable in the wireless network - Windows Mobile 6.5 - C/C++

I wrote a small C/C++ Windows Mobile 6.5 client-application that is connecting to a server and sends some data to this server. The server is in my internal wireless network and is not reacheable outside.
The weird behaviour I'm having:
1) Even if the WIFI is not started on my mobile device, the connect() from the client-application returns success (!= SOCKET_ERROR), which is not the case b/c the server is reacheable only in the wireless network.
2) If the WIFI is not started on my mobile device, if there is a Sleep(1000) between the connect() and the send(), the send() fails with WSAECONNRESET, BUT if there is no Sleep() between the connect() and send() the send() succeeds! (only when doing the read() I finally get the WSAECONNRESET error).
Can somebody pls point me some tips why do I have this behaviour. It's pretty scary that without actually being able to reach the server I still get success for the connect() and for the send() :(
As requested, here is a sample code:
#include <windows.h>
#include <Winsock2.h>
#include "dbgview.h"
# define FxMemZero(buf,len) RtlZeroMemory ((VOID*)(buf),(SIZE_T)(len))
# define FxMemCopy(dst,src,len) RtlCopyMemory ((VOID*)(dst),(CONST VOID*)(src),(SIZE_T)(len))
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
SOCKET proxy_connection;
WSADATA wsadata;
if( 0 != WSAStartup (MAKEWORD(1, 1), &wsadata))
return -1;
proxy_connection = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if(proxy_connection == INVALID_SOCKET) {
// error creating the socket
DbgViewTraceError((L"main", L"error creating socket."));
return -1;
}
// try to connect
UINT proxy_ip_ = 0x00000000;
CHAR* proxy_0_ = "192.168.1.105";
UINT proxy_port = 3100;
// get the proxy ip
{
struct hostent *he_;
if((he_ = gethostbyname(proxy_0_)) == NULL) {
DbgViewTraceWarning((L"main", L"error %d resolving hostname %hs", WSAGetLastError(), proxy_0_));
return -1;
}
FxMemCopy((PBYTE)&proxy_ip_, (PBYTE)he_->h_addr, he_->h_length);
}
// prepare the connection data
sockaddr_in saddr_;
FxMemZero(&saddr_,sizeof(sockaddr_in));
saddr_.sin_family = AF_INET;
saddr_.sin_addr.S_un.S_addr = proxy_ip_;// address
saddr_.sin_port = htons((USHORT)proxy_port);
// do the conection
if(SOCKET_ERROR == connect(proxy_connection, (SOCKADDR*) &saddr_, sizeof(saddr_))) {
// error connecting to the proxy
DbgViewTraceWarning(( L"main", L"error %d connecting to %hs:%d", WSAGetLastError(), proxy_0_, proxy_port));
closesocket(proxy_connection);
proxy_connection = INVALID_SOCKET;
return -1;
}
DbgViewTraceInfo(( L"main", L"SUCCESS. connected to %hs:%d.", proxy_0_, proxy_port));
CHAR* buffer_ = "Momo";
UINT count_ = strlen(buffer_);
DWORD total_ = 0;
DWORD sent_ = 0;
while(total_ < count_) {
// ISSUE: IF the WIFI is not started on the mobile, the connect returns success AND the send() returns success, even though with putty
// on the mobile, a telnet on 192.168.1.105:3100 will fail with: "Network error: Connection reset by peer"
// IF I add a long-enough Sleep() between the connect() and the send(), the send() will fail with: WSAECONNRESET
//Sleep(5000);
if(SOCKET_ERROR == (sent_ = send(proxy_connection, (const char*)buffer_ + total_, count_ - total_, 0))) {
// error sending data to the socket
DbgViewTraceError((L"main", L"error %d sending data to proxy", WSAGetLastError()));
return -1;
}
total_ += sent_;
}
DbgViewTraceInfo((L"main", L"send() SUCCESS"));
return 0;
}
The results are:
1) Without Sleep():
main [INFO ] SUCCESS. connected to 192.168.1.105:3100.
main [INFO ] send() SUCCESS
2) With Sleep():
main [INFO ] SUCCESS. connected to 192.168.1.105:3100.
main [ERROR ] error 10054 sending data to proxy
So the questions are:
1) Why the connect() succeeds? How can I be sure that there is actually a real connection?
2) Why the send() succeeds?
3) Why with a Sleep() in between connect() and send() the behaviour is different?
The problem seems to be ActiveSync. If ActiveSync is running, I get the behavior described above (connect() and send() report success, even though they are not). If ActiveSync is not running, gethostbyname() fails with:
WSAENETDOWN -> if WIFI is disabled
WSAHOST_NOT_FOUND -> if WIFI is enabled
which is correct!
How can this be? What is ActiveSync doing that is ruining everything? How can I avoid this problem? I mean, I can't be sure that the user is running my application when there is no ActiveSync running, so what can I do to avoid this behavior when ActiveSync is running?
Thx,
MeCoco
Looks like you are at least misusing struct sockaddr_in. Try more modern API for address conversion - Windows has InetPton - and see if that fixes the issues.

SO_REUSEADDR with UDP datagrams - Resource unavailable

I'm using SO_REUSEADDR option, but I'm not sure why am getting
Resource temporary unvailable option.
I'm testing client server code on 127.0.0.1
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
{
perror("socket() error!!\n");
exit(1);
}
if ( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse) ) < 0 ) {
perror("SO_REUSEADDR failed::");
exit(1);
}
while(1) {
nbytes_read = recvfrom(sockfd, (void *)&recvd_msg, sizeof(recvd_msg),
flags, &from, &from_len);
printf("nbytes_read = %d\n", nbytes_read);
if(nbytes_read == -1) {
perror("client: recvfrom() failed");
return FAILED;
}
if (nbytes_read > 0) {
if(recvd_msg.hdr.msgtype == DATA)
printf("recvd %d bytes from server\n", recvd_msg.hdr.payload_size);
ftp_show_payload(&recvd_msg);
}
if(recvd_msg.hdr.is_last == TRUE) {
break;
}
}
Error message:
" client: recvfrom() failed: Resource temporarily unavailable"
errno:11
After trying to run client for 3-4 times, I get the data, I'm not sure whats happening.
Also, this problem is on Ubuntu Linux, but when I run the same client server on Solaris,
it works fine!!
SO_REUSEADDR is useful when you use bind(), but here you are not using bind.
I dont see any problem if recvfrom() returns -1
Use bind() and replace your call recvfrom() with recv(). recv() will receive all the packets at the port you used in your bind call.
Are you trimming out any other socket configuration? EAGAIN is typically returned when you read a non-blocking socket and there's no data available. The manpage for recvfrom lists the possible errnos that will be set on failure with an explanation for each one.
Your test is invalid. recvfrom() can return zero, which doesn't indicate an error. It is only valid to call perror() if you get -1. So you may not have a problem at all ..
I don't see why you're using SO_REUSEADDR at all here, as you're not binding to a specific port.