How to send data over tcp to ESP8266 with python? - python

I want to send data from my computer to ESP8266 over TCP. I wanted to do this with python. I programmed ESP with arduino-language with libraries for it, and reciving is simply:
while(client.available()){
String in = client.readStringUntil('~');
//i use '~' instead of '\n' as end character because i often can't send '\n' from tcp android apps
...
}
I use built-in socket library for python, this is how i try to send data:
server_ip = '192.168.1.100'
server_port = 3000
soc = socket.socket()
soc.connect((server_ip, server_port))
soc.send("mydata")
but i'm still getting error "TypeError: a bytes-like object is required, not 'str'". I tried .sendall etc, and sometimes they work, but then my ESP restarts for some reason, maybe encoding? Could someone give me staight path to just send basic string, even with ascii-only characters?

Ok i did
.sendall(text.encode('utf-8')
and figured out that i forget about '~', now everything works :)

Check out this project at github for communication between nodemcu and python over ip
https://github.com/wahajmurtaza/NodeMCU-Python-Wifi

Related

About the issue that the character string is broken in TCP/IP communication between different machines

I tried TCP/IP communication between the same machine and TCP/IP communication between different machines.
First of all, I tried communication in the same Windows machine.The server and client code used is:
TCP_server.py
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 50001))
s.listen(1)
while True:
conn, addr = s.accept()
with conn:
while True:
data = conn.recv(30000)
if not data:
break
if len(data.decode('utf-8')) < 35:
print("error")
break
print(data.decode('utf-8')+"\n")
TCP_client.py
# -*- coding : UTF-8 -*-
import socket
target_ip = "192.168.1.5"
target_port = 50001
buffer_size = 4096
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.connect((target_ip,target_port))
message = b'123456789101112131415161718192021222324252627282930\n'
while True:
tcp_client.send(message)
The IP address of my Windows machine is 192.168.1.5, so the above code works. And it executed successfully without any error. The printed string is shown in the image below.
But when I tried to communicate with Mac and Windows using the exact same code, I had a problem. I used a Mac for the client and Windows for the server.The character string output on the server side is as follows.
As you can see from the image above, it is normally printed normally, but sometimes a line break is made and the character string is divided.
And my server-side code says that if the number of characters is less than 35, it will print error. However, error is not printed in this execution result.In other words, communication is not performed twice, but line breaks are inserted in one communication.
Is it possible to avoid this problem? Do I always have to be aware of line breaks when sending from another machine over TCP/IP?
I'm only using Python in this sample, but I had a similar problem using iOS's Swift for client-side code. So I would like to know a general solution.
There is no line break added by transmission of the data. This line break is instead added by the server code:
print(data.decode('utf-8')+"\n")
Both the print itself causes a line break and then you also add another one.
In general you are assuming that each send has a matching recv. This assumption is wrong. TCP is a byte stream and not a message stream and the payloads from multiple send might be merged together to reduce the overhead of sending and it might also cause a "split" into a single "message".
This is especially true when sending traffic between machines since the bandwidth between the machines is less than the local bandwidth and the MTU of the data layer is also much smaller.
Given that you have to first collect your "messages" at the server side. Only after you've got a complete "message" (whatever this is in your case) you should decode('utf-8'). Otherwise your code might crash when trying to decode a character which has a multi-byte UTF-8 encoding but where not all bytes were received yet.

Python sockets error TypeError: a bytes-like object is required, not 'str' with send function

I am trying to create a program that will open a port on the local machine and let others connect into it via netcat. My current code is.
s = socket.socket()
host = '127.0.0.1'
port = 12345
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
print('Got connection from', addr)
c.send('Thank you for connecting')
c.close()
I am new to Python and sockets. But when I run this code it will allow me to send a netcat connection with the command:
nc 127.0.0.1 12345
But then on my Python script I get the error for the c.send:
TypeError: a bytes-like object is required, not 'str'
I am basically just trying to open a port, allow netcat to connect and have a full shell on that machine.
The reason for this error is that in Python 3, strings are Unicode, but when transmitting on the network, the data needs to be bytes instead. So... a couple of suggestions:
Suggest using c.sendall() instead of c.send() to prevent possible issues where you may not have sent the entire msg with one call (see docs).
For literals, add a 'b' for bytes string: c.sendall(b'Thank you for connecting')
For variables, you need to encode Unicode strings to byte strings (see below)
Best solution (should work w/both 2.x & 3.x):
output = 'Thank you for connecting'
c.sendall(output.encode('utf-8'))
Epilogue/background: this isn't an issue in Python 2 because strings are bytes strings already -- your OP code would work perfectly in that environment. Unicode strings were added to Python in releases 1.6 & 2.0 but took a back seat until 3.0 when they became the default string type. Also see this similar question as well as this one.
You can decode it to str with receive.decode('utf_8').
You can change the send line to this:
c.send(b'Thank you for connecting')
The b makes it bytes instead.
An alternative solution is to introduce a method to the file instance that would do the explicit conversion.
import types
def _write_str(self, ascii_str):
self.write(ascii_str.encode('ascii'))
source_file = open("myfile.bin", "wb")
source_file.write_str = types.MethodType(_write_str, source_file)
And then you can use it as source_file.write_str("Hello World").

Raw load found, how to access?

To start off, I have read through other raw answers pertaining to scapy on here, however none have been useful, maybe I am just doing something wrong and thats what has brought me here today.
So, for starters, I have a pcap file, which started corrupted with some retransmissions, to my belief I have gotten it back to gether correctly.
It contains Radiotap header, IEEE 802.11 (dot11), logical-link control, IPv4, UDP, and DNS.
To my understanding, the udp packets being transmitted hold this raw data, however, do to a some recent quirks, maybe the raw is in Radiotap/raw.
Using scapy, I'm iterating through the packets, and when a packet with the Raw layer is found, I am using the .show() function of scapy to view it.
As such, I can see that there is a raw load available
###[ Raw ]###
\load \
|###[ Raw ]###
| load = '#\x00\x00\x00\xff\xff\xff\xff\xff\xff\x10h?'
So, I suppose my question is, how can I capture this payload to receive whatever this may be, To my knowledge the load is supposed to be an image file, however I have trouble believing such, so I assume I have misstepped somewhere.
Here is the code I'm using to achieve the above result
from scapy.all import *
from scapy.utils import *
pack = rdpcap('/home/username/Downloads/new.pcap')
for packet in pack:
if packet.getlayer(Raw):
print '[+] Found Raw' + '\n'
l = packet.getlayer(Raw)
rawr = Raw(l)
rawr.show()
Any help, or insight for further reading would be appreciated, I am new to scapy and no expert in packet dissection.
*Side note, previously I had tried (using separate code and server) to replay the packets and send them to myself, to no avail. However I feel thats due to my lack of knowledge in receipt of UDP packets.
UPDATES - I have now tested my pcap file with a scapy reassembler, and I've confirmed I have no fragmented packets, or anything of the sort, so I assume all should go smoothly...
Upon opening my pcap in wireshark, I can see that there are retransmissions, but I'm not sure how much that will affect my goals since no fragmentation occurred?
Also, I have tried the getlayer(Raw).load, if I use print on it I get some gibberish to the screen, I'm assuming its the data to my would-be-image, however I need to now get it into a usable format.
You can do:
data = packet[Raw].load
You should be able to access the field in this way:
l = packet.getlayer(Raw).load
Using Scapy’s interactive shell I was successful doing this:
pcap = rdpcap('sniffed_packets.pcap')
s = pcap.sessions()
for key, value in s.iteritems():
# Looking for telnet sessions
if ':23' in key:
for v in value:
try:
v.getlayer(Raw).load
except AttributeError:
pass
If you are trying to get the load part of the packet only, you can try :
def handle_pkt(pkt):
if TCP in pkt and pkt[TCP].dport == 5201:
#print("got a packet")
print(pkt[IP])
load_part = pkt[IP].load
print("Load#",load_part)
pkt.show2()
sys.stdout.flush()

Pyserial testing

I am new to Pyserial and Hardware area. I am trying to run the sample applications given in http://pyserial.sourceforge.net/shortintro.html#opening-serial-ports
import serial
ser = serial.Serial(0) # open first serial port
print ser.portstr # check which port was really used
ser.write("hello") # write a string
ser.close()
I have written this program in a python file and running it. Now if I want to test this application to check if I am sending correct string (eg: Hyperterminal or something) how can I do this. Can anyone guide me?
Use virtual serial port for your test.
For Windows I use com0com and socat for Linux.
Then, use Putty for visualization of your send.
Another quick way to test a physical serial port is to take a wire/screwdriver, crocodile clamp or anything that you have in hand and bridge the RX and TX (receive and transmit) together. At that point, everything that you send out will be looped back at you. YOu can receive it afterward by using this code snippet here:
import serial
ser = serial.Serial(0, timeout = 1) # open first serial port
print ser.portstr # check which port was really used
ser.write("hello") # write a string
msg = ser.read("100") #read the content of the input buffer until you get 100 byte or a timeout event
print(msg) #print the content you might need to decode it print(decode(msg))
ser.close()
The key aspect again for this code to work properly is to bridge RX and TX together. A lot of tutorial will show you how to do this.

Send raw ethernet packet with data field length in type field

I'm trying to send a raw ethernet frame with the length of my data written in the type field. This should be a valid ethernet frame. My code for this looks like this:
ethData = "foobar"
proto =len(ethData)
if proto < 46:
proto = 46
soc = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, proto)
soc.bind((iface, proto))
For some reason I cant read package on the other end. I wonder why. I try to get this package in the interrupt handler of my wireless driver, so this packet has to be droped by my hardware directly or it doesn't get send at all. The question is why.
Sorry, my fault. I just parsed the wrong portion of the packet and didn't get any output. My bad. The package gets there just like it is supposed to.

Categories

Resources