#TCP server-client
1 messages · Page 1 of 1 (latest)
Roger that! Give me a sec
btw, I'm initially going to try it on devices I have updated to latest S3 CircuitPython (yesterday)
Got it!
I don't think the socket code has changed in ages tho
it's fine, it's been awhile, so I loaded up my examples, which still work. that's re-assuring
we should be able to figure it out
Client (computer-python)
import socket
HOST = "192.168.1.188" # The server's hostname or IP address
PORT = 80 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(None)
print("Connecting")
s.connect((HOST, PORT))
print("Sending")
s.send(b"Hello!")
print("Receiving")
data = s.recv(1024)
print("Received", repr(data))
Server (featherS2-citcuitpython)
import wifi
import socketpool
try:
from secrets import secrets
except ImportError:
print("WiFi WiFi secrets are kept in secrets.py, please add them there!")
raise
TIMEOUT = None
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
pool = socketpool.SocketPool(wifi.radio)
print("Finding IP address")
print(wifi.radio.ipv4_address)
HOST = str(wifi.radio.ipv4_address)
PORT = 80 # Port to listen on
print("Creating socket")
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
print("Accepting connections")
conn, addr = sock.accept()
with conn:
print("Connected by", addr)
buff = bytearray(200)
print("Receiving")
numbytes = conn.recvfrom_into(buff)
print(buff[: numbytes[0]])
if numbytes:
print("Sending messages")
conn.send(buff[: numbytes[0]])
Let me know if you need clarification
OK, missed you have CPython server, got that working with my examples, now let me load up this code above...
oh, oops, got that backwards, well I'll just try it
ok, that worked
I changed the IP address to match mine. I also changed the port number since I have something else on 80... I used 5003 (any larger number works that doesn't conflict)
Server:
Connecting to ****
Connected to ****!
Finding IP address
192.168.6.147
Creating socket
Accepting connections
Connected by ('192.168.5.32', 20970)
Receiving
bytearray(b'Hello!')
Sending messages```
Client:
Sending
Receiving
Received b'Hello!'```
Oh sweet! But the port number shouldn't be the issue...besides the port number, Everything is the same in the code??
yeah, but it's a one-shot. If I put both in while True loops, I get the EAGAIN on round 2
I see...hmmm this is a tricky issue
oh, b/c the accept in the server needs to be in the while True
OK, it's working...
so here's my ESP32-S2 Server right now:
You mean conn, addr = sock.accept() needs to be in While True?
yeah
import wifi
import socketpool
try:
from secrets import secrets
except ImportError:
print("WiFi WiFi secrets are kept in secrets.py, please add them there!")
raise
TIMEOUT = None
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
pool = socketpool.SocketPool(wifi.radio)
print("Finding IP address")
print(wifi.radio.ipv4_address)
HOST = str(wifi.radio.ipv4_address)
PORT = 5003 # Port to listen on
print("Creating socket")
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
while True:
print("Accepting connections")
conn, addr = sock.accept()
with conn:
print("Connected by", addr)
buff = bytearray(200)
print("Receiving")
numbytes = conn.recvfrom_into(buff)
print(buff[: numbytes[0]])
if numbytes:
print("Sending messages")
conn.send(buff[: numbytes[0]])
CPython (macOS) Client:
import time
import socket
HOST = "192.168.6.147" # The server's hostname or IP address
PORT = 5003 # The port used by the server
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(None)
print("Connecting")
s.connect((HOST, PORT))
print("Sending")
s.send(b"Hello!")
print("Receiving")
data = s.recv(1024)
print("Received", repr(data))
time.sleep(5)
not much changed
yup, with accept inside
there are a ton of ays to do this... depends on how you want it to behave... blocking, timeouts, retries, error-handling, etc
I can only imagine...So the reason why the first time it didn't work is because...Iol I can't word it out
Because I'm not fully understanding why the continuous loop for while true works and the without the loop does not work
not sure, I only got the EGAIN when I put in the while True but didn't have the accept inside
your initial code worked for me as a one-shot
presumably the server always runs, the client can quit and start up and re-connect later
So one always runs and fhe client is not always running
This even works with multiple clients, just tested that out
the client can always run, but it can go away and come back if you want
Good luck! come back with any more snags. For some reason, I enjoy this stuff, but I've been away from it for months.
Roger that! Thank you
Hello @gloomy trellis ! Hope you had a great Tuesday
I am reaching out to you again because I tried to implement the modified code you showed me
it sill gives me the same error
As you can see the output, line 43 and 40 are causing the trouble.
I tried to search how I could fix it but I did not make any progress on it.
Hi binny, ok give me a sec to get back in the groove 🙂
buff is where the bytes will be placed, and numbytes is an integer telling how many bytes were received
but you are just wanting to print the first 50 bytes and re-send those
so: ```py
print(buff[:50])
...
conn.send(buff[:50])
or, with explicit indices in the slice: ```py
print(buff[0:50])
...
conn.send(buff[0:50])
I was actually wondering what "buff" meant. I couldn't find any websites that explained buff well for me.
Imma try to modify the code tonight and see how it works.
I tried the print(buff[0:50])
...
conn.send(buff[0:50])
But it still gave me this output:
I've been reading this Github post; it seems like this person went through the same thing.
The person figured the problem but I don't know what he specifically did. I read #4049 and I tried what that was, but it seems like im going to a deeper rabbit hole. I got no lead.
I try to start a TCP server on my Lilygo TTGO T8 ESP32-S2 with display. code.py output: 192.168.43.83 will timeoutTraceback (most recent call last): File "code.py", line 18, in &a...
EAGAIN can probably be solved with an appropriate timeout or blocking setting. Can you post the code rather than screen shots? That makes it much easier for me to read, put on my own device, and manipulate.
Networks errors are a fact of life. Exceptions give you a way of detecting and recovering from various problems. Get comfortable with the python try / except construct. Something like:```py
with conn:
conn.settimeout(None)
print("Accepted from", addr)
try:
size = conn.recv_into(buf, MAXBUF)
print("Received", buf[:size], size, "bytes")
conn.send(buf[:size])
print("Sent", buf[:size], size, "bytes")
except OSError as e:
# OSError: [Errno 11] EAGAIN
print("OSError", e)```
Exceptions will surface on the client too, and similar handling will let you skip, or retry, or whatever behavior you want. Over a couple of hours of running the client on my desktop computer, I got: # socket.timeout: timed out # OSError: [Errno 65] No route to host # OSError: [Errno 64] Host is downso there would need to be some handling of things like that.
Hello again @gloomy trellis ! This is my original code. I tried with print(buff[:50]) but it still does not work
server side:
import wifi
import socketpool
try:
from secrets import secrets
except ImportError:
print("WiFi WiFi secrets are kept in secrets.py, please add them there!")
raise
TIMEOUT = None
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
pool = socketpool.SocketPool(wifi.radio)
print("Finding IP address")
print(wifi.radio.ipv4_address)
HOST = str(wifi.radio.ipv4_address)
PORT = 5003 # Port to listen on
print("Creating socket")
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
while True:
print("Accepting connections")
conn, addr = sock.accept()
with conn:
print("Connected by", addr)
buff = bytearray(200)
print("Receiving")
numbytes = conn.recvfrom_into(buff)
print(buff[: numbytes[0]])
if numbytes:
print("Sending messages")
conn.send(buff[: numbytes[0]])
client side:
import time
import socket
HOST = "192.168.1.188" # The server's hostname or IP address
PORT = 80 # The port used by the server
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(None)
print("Connecting")
s.connect((HOST, PORT))
print("Sending")
s.send(b"Hello!")
print("Receiving")
data = s.recv(1024)
print("Received", repr(data))
time.sleep(5)
you can have it format by doing this:
you can edit previous posts too, to keep the chat easier
(that's a backtick, to the left of the "1" key on US keyboard)
what does "does not work" mean?
hold on
I got you
when I typed in print(buff[:50]) instead of print(buff [ : numbytes[50]])
it still gave me EAGAIN error 11
the ports don't match
80 on client, 5003 on server
when I make the ports match, this works
you will get exceptions from time to time, they need to be handled in the code with try / except
if you post the full exception trace (with line numbers), I can probably make some suggestions
oh yeah haha sorry. I just changed the port
I'm still learning about circuitpython, so when you say post the full exception trace, are you saying the output in the REPL??
right, the errors and line numbers where they happen
gotcha
Here is the code that I modified
import wifi
import socketpool
try:
from secrets import secrets
except ImportError:
print("WiFi WiFi secrets are kept in secrets.py, please add them there!")
raise
TIMEOUT = None
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
pool = socketpool.SocketPool(wifi.radio)
print("Finding IP address")
print(wifi.radio.ipv4_address)
HOST = str(wifi.radio.ipv4_address)
PORT = 80 # Port to listen on
print("Creating socket")
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
buf = bytearray(200)
while True:
print("Accepting connections")
conn, addr = sock.accept()
with conn:
conn.settimeout(None)
print("accepted from", addr)
try:
size = conn.recv_into(buf, MAXBUF)
print("received", buf[:size], "bytes")
conn.send(buf[:size])
print("sent", buf[:size], size, "bytes")
except OSError as e:
print("OSError",e)
And here is the output when I ran it
how we define "buf" here?
and why are we defining "buf"?
you are using .recv_into(buf, MAXBUF), where the server code allocates some memory for the incoming bytes. That chunk of memory is the variable called buf (which isn't defined anywhere, we'll get back to that). The MAXBUF also puts a limit on how many bytes you will read... you don't want to read more than the buffer can hold.
so you're just missing that buff = bytearray(200) line you had in here before
put that outside of your loop
it will get re-used for each new accept/receive, so you aren't using up all kinds of memory with more and more packets
I've modified it. Let me run it.
it's working here once I defined buf
also MAXBUF needs to be defined up top somewhere, or use a number in its place
right
jinx
or put a number in buf = bytearray(200)
can it be any integer??
the advantage of using a constant and defining it at the top is it's easy to change since it's used in multiple places
less error-prone
print("Finding IP address")
print(wifi.radio.ipv4_address)
HOST = str(wifi.radio.ipv4_address)
PORT = 5003 # Port to listen on
MAXBUF = 200
print("Creating socket")
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
buf = bytearray(MAXBUF)
while True:
print("Accepting connections")
conn, addr = sock.accept()
with conn:
conn.settimeout(None)
print("accepted from", addr)
try:
size = conn.recv_into(buf, MAXBUF)
print("received", buf[:size], "bytes")
conn.send(buf[:size])
print("sent", buf[:size], size, "bytes")
except OSError as e:
print("OSError",e)
if you get an occasional exception on the server, you'll also probably get one at the client at that time (and probably other times too), so the client will eventually need some try / except too
just to clarify
when you get exceptions, look them up so you know if you just forgot something in the code, or if it's some network glitch that you need to add exception-handling for
exactly... it tries to do the first chunk of stuff, and if it gets the type of exception you identify in the except, then it will do that chunk
you can have multiple except sections, and even more things... they can be really powerful, may want to read up on them sometime
no no THANK YOU for helping
np, I know it's a learning curve, I started in the same place two three years ago
Gotcha!
I got one more question
so I understand the logic behind the coding until we get to with conn:
with conn:
conn.settimeout(None)
print("accepted from", addr)
try:
size = conn.recv_into(buf, MAXBUF)
print("received", buf[:size], "bytes")
conn.send(buf[:size])
print("sent", buf[:size], size, "bytes")
except OSError as e:
print("OSError",e)
after the line with conn: , I'm kinda lost how the logic behind the coding works
this is a common kind of socket: TCP, the same kind that's used by HTTP in the browser
the server creates a socket, the bind and listen set up the server to be ready at a certain IP address and port
yes! so the general picture I get it
accept is what actually receives the request from the client to connect.
but for conn.settimeout(None), it means that there is no "resting period" between the connection??
ok, so with conn: is a context manager, it just keeps things clean so that when that block exits the socket gets closed autonatically (otherwise you'd have a close(s) at the end of the inner block)
conn.settimeout(None) is setting the server socket to "blocking", meaning it will not timeout
it will sit there forever waiting for a client
inside the with conn: block, you have access to the conn and addr variables (and all the constants and variables from above)
try is a general Python concept, it basically sets up for an except so the code doesn't stop running if something happens
it will print that message, then continue on to the next iteration of the while True: loop
Understood!
(closing the socket first since there's a with)
For "size = conn.recv_into(buf, MAXBUF)"
it is allowing the socket to receive data correct? buf is the chunk of memory
and MAXBUF is how much it can handle
the server reads bytes from the accepted socket connection, and places them into it's own buffer, buf, up to MAXBYTES bytes
size tells you the actual number of bytes it received
ah ha gotcha
maybe the client had a problem and the server only got 3 bytes
hmmm maybe
this is my client code
import time
import socket
HOST = "192.168.1.188" # The server's hostname or IP address
PORT = 80 # The port used by the server
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(None)
print("Connecting")
s.connect((HOST, PORT))
print("Sending")
s.send(b"Hello!")
print("Receiving")
data = s.recv(1024)
print("Received", repr(data))
time.sleep(5)
going back to our server code
print("received", buf[:size], "bytes") means that the server display the string from the client
with the data size that we defined earlier
it prints (displays) the bytes (bytearray) we received, and the length of that bytearray
(not string ...bytes are just values from 0-255, a string is text that is in a certain format like ASCII or UTF-8
well, you want the bytearray to be large enough to handle what you expect from the client
gotcha gotcha
got it! so if bytes are values from 0-255, how can display texts that I wrote in the client side?
you could make a bytearray(10000), but only .recv_into(buf, 15)
to print bytes or bytearray`, you have to get them into string form
there are a few ways to do this...
got it...I think I can look this information up in more detail and save your time 😉
I think I got all the information that I need to process through the code and make it truly mine
cool, yeah it just takes messing around with variations, and tutorials help... reading or videos depending how you learn best
good luck!
@gloomy trellis Appreciate it! Thank you so much for your help
oh and one more thing, where is the place to practice circuit python?? Based on your experience??
"best
there's a pinned tweet in the #help-with-circuitpython channel that has a bunch of resource links
well, CircuitPython is designed to tun on microcontrollers (like your server... did I ever ask what it was?)
but most code will run on any of the CircuitPython-capable boards
Gotcha!
people do all kinds of stuff with them... check the Adafruit Learn Guides, narow down with searching on your interests
I gotta utilize this discord channel more
Is this TCP server-client chat going to disappear later? Because I would like this chat to be here as long as possible lol
socket stuf like your cocde neds ESP32-S2 (or ESP32-S3) boards, although there are variations for other boards with wifi of another flavor, or for ethernet
I believe it stays here forever, though it gets "archived" after some hours, then you can find it at the top, that leftmost icon
You're welcome!
Hello @gloomy trellis! Hope you had a great Thursday
Thanks to you I was able to make the code where the client(computer) can send a command to the server(feather) to light up using the imbedded led light in the micro controller.
And I am trying to further develop my code to so that I can send more complex commands from my client to the server.
I am trying to separate two strings, but when I run the code, they come out together.
Observe
import time
import socket
HOST = "192.168.1.188" # The server's hostname or IP address
PORT = 80 # The port used by the server
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(None)
print("Connecting")
s.connect((HOST, PORT))
print("Sending")
s.send(b"Hello! Sending commands now")
s.send(b" blink")
print("Receiving")
data = s.recv(1024)
print("Received", repr(data))
time.sleep(5)
I am trying to separate "Hello! Sending commands now" and "blink" but I don't know what to do.
Well, it's just bytes being sent and received, You could send separate strings (bytes) in separate connections, or you could add in a separator (byte or sequence) that the receiver interprets.
🎉 for getting it to do stuff on the receivng end 🙂
At the TCP socket level, you are guaranteed that bytes will arrive in order, and best attempt to get all the bytes to arrive. But the server and client are completely free to determine what those bytes mean or do. Unlike HTTP, for example, which runs on top of TCP but has defined byte sequences that mean specific things to the client and server.
(like how to split the headers from the body, and several ways to know that the transmission is complete)
Gotcha...I guess this leads me to the next questions
*question
So the concept that I am thinking now is that, every time when the server receives "blink" I want the feather S2 to blink
But right now, I am using the size of the string (bytes) to light up my LED
for example my server code is this:
import board
import digitalio
import time
import wifi
import socketpool
try:
from secrets import secrets
except ImportError:
print("WiFi WiFi secrets are kept in secrets.py, please add them there!")
raise
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
TIMEOUT = None
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
pool = socketpool.SocketPool(wifi.radio)
print("Finding IP address")
print(wifi.radio.ipv4_address)
HOST = str(wifi.radio.ipv4_address)
PORT = 80 # Port to listen on
MAXBUF = 200
print("Creating socket")
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
buf = bytearray(MAXBUF)
while True:
print("Accepting connections")
conn, addr = sock.accept()
with conn:
conn.settimeout(None)
print("accepted from", addr)
try:
size = conn.recv_into(buf, MAXBUF)
print("received", buf[:size],size, "bytes")
if size>20:
led.value = True
time.sleep(6)
led.value = False
time.sleep(1)
conn.send(buf[:size])
print("sent", buf[:size], size, "bytes")
except OSError as e:
print("OSError",e)
as you can see, when the byte size is more than 20, I coded the LED to light up
but I want the code to recognize "blink"
When the server receives, it comes out like this
the question is how can I pick "blink" using bytes that are coming in order?
I try to look up hints in google but Im lost
does this help:```py
y = bytearray(b'qwertyuiop')
if b'erty' in y:
... print("Found it!")
...
Found it!```
ahhhhhhhhhh!
(find a sub-"string" in a "string" - bytes / bytearray really)
I see the concept here
I am going to play around with it and see what I could do
Thanks for providing the hint @gloomy trellis
np, good luck!
Thank you!!!
Hello @gloomy trellis! Hope you are doing well
So I was successfully able to create a code that can make the mini vibrator buzz in certain conditions.
Here is the code:
'''py
import board
import digitalio
import time
import wifi
import socketpool
import busio
#About busio: https://circuitpython.readthedocs.io/en/3.x/shared-bindings/busio/__init__.html
import adafruit_drv2605
#This is the haptic controller
try:
from secrets import secrets
except ImportError:
print("WiFi WiFi secrets are kept in secrets.py, please add them there!")
raise
#This will import the secret file which contains the password and the name of the wifi network
i2c = busio.I2C(board.SCL,board.SDA)
#I2C: is a communication bus designed by Philips, for chips to communicate with each other on a PCB.
#In this case, we are trying to communicate with our feather S2 and the haptic controller.
#board.SCL(serial clock line) and board.SDA(serial data line): think of it as creating the necessary pins of the virtual board.
drv = adafruit_drv2605.DRV2605(i2c)
#Putting the communication tool i2c in the haptic controller
#Establish communitcation between feather S2 and haptic controller using I2C
TIMEOUT = None
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
pool = socketpool.SocketPool(wifi.radio)
print("Finding IP address")
print(wifi.radio.ipv4_address)
HOST = str(wifi.radio.ipv4_address)
PORT = 80 # Port to listen on
MAXBUF = 200
effect_number_1 = 14;
effect_number_2 = 15;
effect_number_3 = 16;
print("Creating socket")
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
buf = bytearray(MAXBUF)
while True:
print("Accepting connections")
conn, addr = sock.accept()
with conn:
conn.settimeout(None)
print("accepted from", addr)
try:
size = conn.recv_into(buf, MAXBUF)
print("received", buf[:size],size, "bytes")
y = buf[:size]
#print(y)
if "effect#1" and "effect#4" in y:
print("Playing effect #{0}".format(effect_number_1))
drv.sequence[0] = adafruit_drv2605.Effect(effect_number_1)
# Set the effect on slot 0.
# You can assign effects to up to 7 different slots to combine
# them in interesting ways. Index the sequence property with a slot number 0 to 6.
drv.play()
time.sleep(1)
drv.stop()
elif "effect#2" in y:
print("Playing effect #{0}".format(effect_number_2))
drv.sequence[1] = adafruit_drv2605.Effect(effect_number_2)
drv.play()
time.sleep(1)
drv.stop()
else:
print("Playing effect #{0}".format(effect_number_3))
drv.sequence[2] = adafruit_drv2605.Effect(effect_number_3)
drv.play()
time.sleep(1)
drv.stop()
conn.send(buf[:size])
print("sent", buf[:size], size, "bytes")
except OSError as e:
print("OSError",e)
It was working fine a month ago; I was working on a different project. And when I came back today to run this code again, I get this outcome.
I thought I had to update my adafruit circuitpython library but that was not the case
it seems like there is a problem with the I2C device and it can not find the address.
I have never seen this problem before.
That often means a hardware / wiring issue. This is a more common issue, you could post a photo and that exception trace in the main #help-with-circuitpython and more people can look at it. What is the hardware setup, how is it wired? Have you tried an I2C scan? https://learn.adafruit.com/circuitpython-essentials/circuitpython-i2c about half way down the page is code for a scan
Ahhhhhh gotcha gotcha
I thought it was the coding problem
Let me try this one thing and if it does not work, I'll post the wiring in the adafruit group chat
and yes I tried an I2C scan and it returned 0×27
You were right @gloomy trellis !! There was a wires that were misplaced.
Thank you for your advice and help :)
Hello hello @gloomy trellis ! Hope you are having a great weekend!!
I need your assistance again
So far, I have mentioned this before, I was able to send an condition from my client side to the server side, so that the server side can play the mini vibrator when it finds certain words.
This is the diagram that I made for people to understand
So we are able to send information from client to the server
Now I am trying to send data from server to the client
but I am having a difficulty with this
I do not want to dump tons of information to you
I want to go step by step
This is my client side code (original form):
import time
import socket
HOST = "192.168.1.188" # The server's hostname or IP address
PORT = 80 # The port used by the server
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(None)
print("Connecting")
s.connect((HOST, PORT))
print("Sending")
s.send(b"Hello! Sending commands now ")
s.send(b"First Command: effect#1")
s.send(b" pause")
s.send(b" second command: effect#2")
s.send(b" pause")
s.send(b" third command: effect#3")
print("Receiving")
data = s.recv(1024)
print("Received", repr(data))
time.sleep(5)
The next one is my modified code so that the client can accept data from the server:
import time
import socket
HOST = "192.168.1.188" # The server's hostname or IP address
PORT = 80 # The port used by the server
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(None)
print("Connecting")
s.connect((HOST, PORT))
print("Sending")
s.send(b"Hello! Sending commands now ")
s.send(b"First Command: effect#1")
s.send(b" pause")
s.send(b" second command: effect#2")
s.send(b" pause")
s.send(b" third command: effect#3")
print("Receiving")
data = s.recv(1024)
print("Received", repr(data))
time.sleep(5)
print("Accepting connections")
while True:
try:
conn, addr = s.accept()
break
except BlockingIOError:
pass
with conn:
data = conn.recv(128)
print("got: " + str(data))
conn.sendall(data)
print("sent: " + str(data))
so far I have gotten only errors
so... TCP socket gets set up, command is sent to server, then that is closed (exit with), so I think there is no socket left to receive data from the server. Or is the intent to switch from client to server (and presumably vice-versa at the other end) ?
what is the exception trace?
I think you want to leave the connection open, then you can just use some form of recv() to read the server's response. (I'm not sure s.accept() here has much meaning since there was no bind or listen)
The intent is to leave it as it is: the feather S2 remaining as the server and the computer side is the client
so on the modified version of the code, the "with" at the end closes the socket??
yes
ahhh gotcha gotcha
let me try this and get back to you
I have to go to church now
well, the accept ...not sure what that's doing
this is the computer client, right?
oh that
so you send a command string, then recv a reply / acknowledgement?
I thought that would allow the client to receive information from the server side
than what? what is the bottom part doing?
So here is the big picture
right after the string command is sent you have this:
print("Receiving")
data = s.recv(1024)
print("Received", repr(data))```
yes
that reads some kind of acknowledgement from the Feather seerver?
ok, so does anything more need to be done, or just loop back up and send a new command?
I want to add more towards it
so here is the thing
Im currently in a project where I am dealing with a dancing robot
and I am working with the haptics function of the robot
I want the dancer (person) and the robot to communitcate
communicate
The first step is to make a code where the robot can tell the dancer that it has finished its task going from A to B
and sending a vibrating signal to the dancer using the mini virbator
and the robot controller is the Feather Server?
not really
the feather s2 will be attached on the dancer
and mini vibrator on it
so the robot will be the client
the feather S2 will be the server
we have finished the first mile stone as you can see my coding
its just a prototype
right, ok, i'm getting the bigger picture I think
now what we want is that we want to implement an accelerometer on the feather S2
so that when the dancer moves a certain movement like a "flick" or stop motion
the robot responds to that
So with TCP, there is a connection, a server, and (at least) one client. You can leave the connection alive and just send and receive back and forth for the duration of the activity.
yes yes
It's also possible to break the connection after each sub-activity and re-establish it for a subsequent sub-activity
so here is my next question
in a sense, with only one client and one server, it doesn't matter (much) which is the client and which is the server... just so they can connect and communicate in two directions
yup yup
I see so it is possible for client and server to communicate both ways
when you said sub activity
yes, and there are many ways to accomplish that depending on your goals, priorities, etc
sub-activity... for example, if each action to be mirrored is a separate connection
but it's easiest to stay connected ...just need to detect the case where something disrupts the connection so that you can re-connect
sounds good
Hello again @gloomy trellis ! I have made some modification on the client side code
import time
import socket
HOST = "192.168.1.188" # The server's hostname or IP address
PORT = 80 # The port used by the server
while True:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(None)
print("Connecting")
s.connect((HOST, PORT))
print("Sending")
s.send(b"Hello! Sending commands now ")
s.send(b"First Command: effect#1")
s.send(b" pause")
s.send(b" second command: effect#2")
s.send(b" pause")
s.send(b" third command: effect#3")
print("Receiving")
data = s.recv(1024)
print("got: " + str(data))
print("Received", repr(data))
time.sleep(5)
it seems the client side is good but i think the server is having a problem now
it seems like the client can not receive what the server is trying to send
this is my server side code
#Basic libraries
import board
import digitalio
import time
#accelerometer libraries:
import adafruit_bno055
import math
import analogio
#Socket libraries
import wifi
import socketpool
import busio
#About busio: https://circuitpython.readthedocs.io/en/3.x/shared-bindings/busio/__init__.html
import adafruit_drv2605
#This is the haptic controller
try:
from secrets import secrets
except ImportError:
print("WiFi WiFi secrets are kept in secrets.py, please add them there!")
raise
#This will import the secret file which contains the password and the name of the wifi network
i2c = busio.I2C(board.SCL,board.SDA)
#I2C: is a communication bus designed by Philips, for chips to communicate with each other on a PCB.
#In this case, we are trying to communicate with our feather S2 and the haptic controller.
#This is for the accelerometer BNO055
##a2c = board.I2C()
##sensor = adafruit_bno055.BNO055_I2C(a2c)
#board.SCL(serial clock line) and board.SDA(serial data line): think of it as creating the necessary pins of the virtual board.
drv = adafruit_drv2605.DRV2605(i2c)
#Putting the communication tool i2c in the haptic controller
#Establish communitcation between feather S2 and haptic controller using I2C
TIMEOUT = None
print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
pool = socketpool.SocketPool(wifi.radio)
print("Finding IP address")
print(wifi.radio.ipv4_address)
HOST = str(wifi.radio.ipv4_address)
PORT = 80 # Port to listen on
MAXBUF = 200
effect_number_1 = 14;
effect_number_2 = 15;
effect_number_3 = 16;
print("Creating socket")
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
buf = bytearray(MAXBUF)
while True:
print("Accepting connections")
conn, addr = sock.accept()
with conn:
conn.settimeout(None)
print("accepted from", addr)
try:
size = conn.recv_into(buf, MAXBUF)
print("received", buf[:size],size, "bytes")
y = buf[:size]
#print(y)
if "effect#1" and "effect#4" in y:
print("Playing effect #{0}".format(effect_number_1))
drv.sequence[0] = adafruit_drv2605.Effect(effect_number_1)
# Set the effect on slot 0.
# You can assign effects to up to 7 different slots to combine
# them in interesting ways. Index the sequence property with a slot number 0 to 6.
drv.play()
time.sleep(1)
drv.stop()
elif "effect#2" in y:
print("Playing effect #{0}".format(effect_number_2))
drv.sequence[1] = adafruit_drv2605.Effect(effect_number_2)
drv.play()
time.sleep(1)
drv.stop()
else:
print("Playing effect #{0}".format(effect_number_3))
drv.sequence[2] = adafruit_drv2605.Effect(effect_number_3)
drv.play()
time.sleep(1)
drv.stop()
conn.send(buf[:size])
sent = sock.send(b"Hello, world")
except OSError as e:
print("OSError",e)
the focus should be this part:
am i on the right track? or am I missing something?
Here are the outputs
Server side:
client side:
Never mind! I think I got it!!
let me put the accelerometer data and see if I can polish the code
lol Im stuck again
how do you send a "tuple"? or how do you send numbers?
This is the code that I have on the server side:
while True:
print("Accepting connections")
conn, addr = sock.accept()
with conn:
conn.settimeout(None)
print("accepted from", addr)
try:
size = conn.recv_into(buf, MAXBUF)
print("received", buf[:size],size, "bytes")
y = buf[:size]
#print(y)
if "effect#1" and "effect#4" in y:
print("Playing effect #{0}".format(effect_number_1))
drv.sequence[0] = adafruit_drv2605.Effect(effect_number_1)
# Set the effect on slot 0.
# You can assign effects to up to 7 different slots to combine
# them in interesting ways. Index the sequence property with a slot number 0 to 6.
drv.play()
time.sleep(1)
drv.stop()
elif "effect#2" in y:
print("Playing effect #{0}".format(effect_number_2))
drv.sequence[1] = adafruit_drv2605.Effect(effect_number_2)
drv.play()
time.sleep(1)
drv.stop()
else:
print("Playing effect #{0}".format(effect_number_3))
drv.sequence[2] = adafruit_drv2605.Effect(effect_number_3)
drv.play()
time.sleep(1)
drv.stop()
#Measureing Linear acceleration
lin_acc = sensor.linear_acceleration
x= lin_acc[0]
y= lin_acc[1]
z= lin_acc[2]
mag = math.sqrt((x*x)+(y*y)+(z*z))
sent = conn.send((mag,))
except OSError as e:
print("OSError",e)
Focusing on this part:
Trying to send the magnitude of these numbers
I was able successfully send words from the server side to the client side
But this one...not sure
you're essentially always sending bytes, ASCII strings are convenient, but for more complex data, you'll have to encode it somehow... as strings / bytes, as json, using msgpack, or some other method... this would be a good question for the main channel, more eyes to see the question and help (and also learn)