#TCP server-client

1 messages · Page 1 of 1 (latest)

gloomy trellis
#

@amber tendon starting a thread. If you can post your code, I can load it up and see what I can

amber tendon
#

Roger that! Give me a sec

gloomy trellis
#

btw, I'm initially going to try it on devices I have updated to latest S3 CircuitPython (yesterday)

amber tendon
#

Got it!

gloomy trellis
#

I don't think the socket code has changed in ages tho

amber tendon
#

I agree

#

Sorry my computer is a bit slow

gloomy trellis
#

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

amber tendon
#

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

gloomy trellis
#

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!'```
amber tendon
#

Oh sweet! But the port number shouldn't be the issue...besides the port number, Everything is the same in the code??

gloomy trellis
#

yeah, but it's a one-shot. If I put both in while True loops, I get the EAGAIN on round 2

amber tendon
#

I see...hmmm this is a tricky issue

gloomy trellis
#

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:

amber tendon
#

You mean conn, addr = sock.accept() needs to be in While True?

gloomy trellis
#

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

amber tendon
#

So pretty much we had to make it as continuous loop

#

Using While True

gloomy trellis
#

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

amber tendon
#

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

gloomy trellis
#

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

amber tendon
#

Gotcha! I'll try the code that you've modified

#

I really appreciate your help

gloomy trellis
#

presumably the server always runs, the client can quit and start up and re-connect later

amber tendon
#

So one always runs and fhe client is not always running

gloomy trellis
#

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

amber tendon
#

I have to try with multiple clients

#

Will run the code tomorrow

gloomy trellis
#

Good luck! come back with any more snags. For some reason, I enjoy this stuff, but I've been away from it for months.

amber tendon
#

Roger that! Thank you

amber tendon
#

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.

gloomy trellis
#

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])

amber tendon
#

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.

amber tendon
#

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.

gloomy trellis
#

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.

gloomy trellis
#

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.

amber tendon
#

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)
gloomy trellis
#

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?

amber tendon
#

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

gloomy trellis
#

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

amber tendon
#

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??

gloomy trellis
#

right, the errors and line numbers where they happen

amber tendon
#

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"?

gloomy trellis
#

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

amber tendon
#

I've modified it. Let me run it.

gloomy trellis
#

it's working here once I defined buf

amber tendon
gloomy trellis
#

also MAXBUF needs to be defined up top somewhere, or use a number in its place

#

right

#

jinx

amber tendon
#

do we need define maxbuf??

#

lolol

#

gotcha

gloomy trellis
#

or put a number in buf = bytearray(200)

amber tendon
#

can it be any integer??

gloomy trellis
#

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)
amber tendon
#

I see I see

#

let me change the port number and run it

gloomy trellis
#

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

amber tendon
#

just to clarify

gloomy trellis
#

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

amber tendon
#

when you say try/ except

#

is it like trial and error??

gloomy trellis
#

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

amber tendon
#

hey @gloomy trellis

#

IT WORKED!!!!!!

gloomy trellis
#

you can have multiple except sections, and even more things... they can be really powerful, may want to read up on them sometime

amber tendon
gloomy trellis
#

but for now, try: / except: will get you a long way

#

boom, you got it!

amber tendon
#

no no THANK YOU for helping

gloomy trellis
#

np, I know it's a learning curve, I started in the same place two three years ago

amber tendon
#

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

gloomy trellis
#

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

amber tendon
#

yes! so the general picture I get it

gloomy trellis
#

accept is what actually receives the request from the client to connect.

amber tendon
#

but for conn.settimeout(None), it means that there is no "resting period" between the connection??

gloomy trellis
#

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

amber tendon
#

ahhhhhh gotcha gotcha

#

try: is a function where it makes the socket do somethnig??

gloomy trellis
#

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

amber tendon
#

Understood!

gloomy trellis
#

(closing the socket first since there's a with)

amber tendon
#

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

gloomy trellis
#

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

amber tendon
#

ah ha gotcha

gloomy trellis
#

maybe the client had a problem and the server only got 3 bytes

amber tendon
#

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

gloomy trellis
#

it prints (displays) the bytes (bytearray) we received, and the length of that bytearray

amber tendon
#

so if the bytearray was small

#

the server would not be able to process it??

gloomy trellis
#

(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

amber tendon
#

gotcha gotcha

gloomy trellis
#

you control how much you read with MAXBUF

#

in the .recv_into

amber tendon
#

got it! so if bytes are values from 0-255, how can display texts that I wrote in the client side?

gloomy trellis
#

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...

amber tendon
#

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

gloomy trellis
#

cool, yeah it just takes messing around with variations, and tutorials help... reading or videos depending how you learn best

#

good luck!

amber tendon
#

@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

gloomy trellis
#

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

amber tendon
#

Gotcha!

gloomy trellis
#

people do all kinds of stuff with them... check the Adafruit Learn Guides, narow down with searching on your interests

amber tendon
#

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

gloomy trellis
#

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

amber tendon
#

Lovely! That is awesome!

#

This chat was very helpful

#

Thank you again!

gloomy trellis
#

You're welcome!

amber tendon
#

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.

gloomy trellis
#

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)

amber tendon
#

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

gloomy trellis
#

does this help:```py

y = bytearray(b'qwertyuiop')
if b'erty' in y:
... print("Found it!")
...
Found it!```

amber tendon
#

ahhhhhhhhhh!

gloomy trellis
#

(find a sub-"string" in a "string" - bytes / bytearray really)

amber tendon
#

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

gloomy trellis
#

np, good luck!

amber tendon
#

Thank you!!!

amber tendon
#

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.

gloomy trellis
amber tendon
#

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

amber tendon
#

You were right @gloomy trellis !! There was a wires that were misplaced.

#

Thank you for your advice and help :)

amber tendon
#

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

gloomy trellis
#

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)

amber tendon
#

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??

gloomy trellis
#

yes

amber tendon
#

ahhh gotcha gotcha

#

let me try this and get back to you

#

I have to go to church now

gloomy trellis
#

well, the accept ...not sure what that's doing

#

this is the computer client, right?

amber tendon
#

oh that

gloomy trellis
#

so you send a command string, then recv a reply / acknowledgement?

amber tendon
#

I thought that would allow the client to receive information from the server side

gloomy trellis
#

than what? what is the bottom part doing?

amber tendon
#

So here is the big picture

gloomy trellis
#

right after the string command is sent you have this:

#
        print("Receiving")
        data = s.recv(1024)
        
        print("Received", repr(data))```
amber tendon
#

yes

gloomy trellis
#

that reads some kind of acknowledgement from the Feather seerver?

amber tendon
#

yes yes

#

but here is the thing

gloomy trellis
#

ok, so does anything more need to be done, or just loop back up and send a new command?

amber tendon
#

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

gloomy trellis
#

and the robot controller is the Feather Server?

amber tendon
#

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

gloomy trellis
#

right, ok, i'm getting the bigger picture I think

amber tendon
#

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

gloomy trellis
#

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.

amber tendon
#

yes yes

gloomy trellis
#

It's also possible to break the connection after each sub-activity and re-establish it for a subsequent sub-activity

amber tendon
#

so here is my next question

gloomy trellis
#

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

amber tendon
#

yup yup

#

I see so it is possible for client and server to communicate both ways

#

when you said sub activity

gloomy trellis
#

yes, and there are many ways to accomplish that depending on your goals, priorities, etc

amber tendon
#

I see

#

for my client code

gloomy trellis
#

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

amber tendon
#

I see

#

I'll take your advice and work on it

#

I'll update you later on my progress

gloomy trellis
#

sounds good

amber tendon
#

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

gloomy trellis
#

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)