How to send data via bluetooth to Pi pico - python
I need a way to send data to and from my pi pico via bluetooth.
Here is the program I'm running on my pc.
Note: Everything on the pi is working correctly (tested with a bt serial terminal)
import bluetooth as bt
print("Scanning Bluetooth Devices....")
devices = bt.discover_devices(lookup_names=True)
for addr, name in devices:
print("%s : %s" % (name, addr))
dev_name = input("Enter device name: ")
dev = ""
check = False
for addr, name in devices:
if dev_name == name:
dev = addr
check = True
if not check:
print("Device Name Invalid!")
else:
print("Attempting to connect to %s : %s" % (dev_name, dev))
hostMACAddress = dev
port = 3
backlog = 1
size = 1024
s = bt.BluetoothSocket(bt.RFCOMM)
s.bind((hostMACAddress, port))
s.listen(backlog)
try:
client, clientInfo = s.accept()
while 1:
data = client.recv(size)
if data:
print(data)
client.send(data) # Echo back to client
except:
print("Closing socket")
client.close()
s.close()
It doesn't throw any errors but I don't get anything printed to the terminal when the pi should send "R"
Edit: Here is the working code for anyone interested :)
import bluetooth as bt
print("Scanning Bluetooth Devices....")
devices = bt.discover_devices(lookup_names=True)
for addr, name in devices:
print("%s : %s" % (name, addr))
dev_name = input("Enter device name: ")
dev = ""
check = False
for addr, name in devices:
if dev_name == name:
dev = addr
check = True
if not check:
print("Device Name Invalid!")
else:
print("Sending data to %s : %s" % (dev_name, dev))
hostMACAddress = dev
port = 1
backlog = 1
size = 8
s = bt.BluetoothSocket(bt.RFCOMM)
try:
s.connect((hostMACAddress, port))
except:
print("Couldn't Connect!")
s.send("T")
s.send("E")
s.send("S")
s.send("T")
s.send(".")
s.close()
The most straight forward (but not the most efficient way) is to convert the array of integer to a delimited C string and send it the way you are sending "Ready".
Let assume the array delimiters are "[" and "]" then the following array
int arr[] = {1,2,3};
can be converted to a string like the following
char str[] = "[010203]";
To convert array of integer to the delimited string you can do the following:
int arr[] = {1,2,3};
int str_length = 50; // Change the length of str based on your need.
char str[str_length] = {0};
int char_written = 0;
char_written = sprintf(str,'[');
for (int i = 0; i< sizeof(arr)/sizeof(int) - 1; i++){
char_written = sprintf(&str[char_written], "%02d", arr[i]);
char_written = sprintf(&str[char_written], ']');
Now you can use your existing code to send this string. In the receiving end, you need to process the string based on "[", "]", and the fact that each integer has width of 2 in the string.
Edit: Converting array to string and send the string via bluetooth via python.
To convert an array to string in python the following will do the job
a = [1,2,3,4,5]
a_string = "[" + "".join(f"{i:02d}" for i in a) + "]"
To send this string via python over bluetooth you need to use PyBlues library.
First you need to find the MAC address of the pico bluetooth
import bluetooth
# Make sure the only bluetooth device around is the pico.
devices = bluetooth.discover_devices()
print(devices)
Now that you know the MAC address, you need to connect to it
bt_mac = "x:x:x:x:x:x" # Replace with yours.
port = 1
sock=bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((bd_addr, port))
Know you can send strings like
sock.send(a_string.encode())
Finally, in the end of your python program close the socket
sock.close()
PS: I do not have bluetooth available to test it but it should work.
Related
Unstable behavior of Mbed 5 and Python 3 over Serial
I have created a Python 3 sketch to try and upload the current NTP time to STM32L476RG Nucleo. The sketch is as follows: import serial import glob import sys import time from socket import AF_INET, SOCK_DGRAM import socket import struct def serial_ports(): """ Lists serial port names :raises EnvironmentError: On unsupported or unknown platforms :returns: A list of the serial ports available on the system """ if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): # this excludes your current terminal "/dev/tty" ports = glob.glob('/dev/tty[A-Za-z]*') elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') else: raise EnvironmentError('Unsupported platform') result = [] for port in ports: try: s = serial.Serial(port) s.close() result.append(port) except (OSError, serial.SerialException): print("OSError or Serial Exception raised, exiting...") pass return result def getNTPTime(host = "pool.ntp.org"): port = 123 buf = 1024 address = (host,port) msg = '\x1b' + 47 * '\0' # reference time (in seconds since 1900-01-01 00:00:00) TIME1970 = 2208988800 # 1970-01-01 00:00:00 # connect to server client = socket.socket( AF_INET, SOCK_DGRAM) while True: try: client.sendto(msg.encode('utf-8'), address) msg, address = client.recvfrom( buf ) t = struct.unpack( "!12I", msg )[10] t -= TIME1970 return t except (socket.gaierror): print("Error! Internet connection not found, exiting...") break my_t_zone = -8 cur_ser = ''.join([s for s in serial_ports() if 'usbmodem' in s]) if(len(cur_ser)>0): ser = serial.Serial(cur_ser) if(not ser.isOpen()): ser.open() valid = 0 time.sleep(.5) while(not valid): ser.reset_input_buffer() line = ser.readline().decode('utf-8').strip() if(line=="Hello"): ntp_time = ("DEA"+str(getNTPTime()+(my_t_zone*3600))+"L").encode('utf_8') ser.write(ntp_time) valid = 1 time.sleep(.5) print("Done uploading time.") ser.close() else: print("No compatible serial device found, exiting...") The Mbed sketch running on the Nucleo board is as follows: #include "mbed.h" Serial pc(USBTX, USBRX); const int kMaxBufferSize = 100; char buffer[kMaxBufferSize]; int len = 0; int contact = 1; void removeChar(char *s, int c){ int j, n = strlen(s); for (int i=j=0; i<n; i++) if (s[i] != c) s[j++] = s[i]; s[j] = '\0'; } int main() { pc.baud(9600); while(contact) { pc.printf("Hello\n"); if (pc.readable() > 0) { char new_char; while(new_char != 'L') { new_char = pc.getc(); buffer[len++] = new_char; } contact = 0; } } removeChar(buffer, 'D'); removeChar(buffer, 'E'); removeChar(buffer, 'A'); removeChar(buffer, 'L'); int x = atoi(buffer); while(!contact) { pc.printf("%s\n",buffer); } } The behavior of the system is unstable. I observe several things: Most of the time this code snippet works fine and Mbed shows the uploaded Posix timestamp properly after parsing. Sometimes erroneous characters are shown in the parsed timestamp (e.g. symbols and other characters) Sometimes the entire posix timestamp is not shown by Mbed and gets cut out. Also, you can see the Python code uploads three characters before the timestamp. These are used to make sure the code works most of the time (i.e. without them first two digits of timestamps get cut out most of the time). Can anyone suggest what’s wrong? Seems like a sync issue.
i want to receive string from python server
I'm making an application using android and Python. android is client python is server i send image file to python and want to receive string from server but No strings are coming from the server. socketIn.readLine() This part does not work. try { // 소켓을 생성하고 입출력 스트립을 소켓에 연결 clientSocket = Socket(ip , port) Log.d("Socket>>>>>>", "ip and port open Success!!!!!") //val inputStream = clientSocket.getInputStream() val tempfile = file try{ socketIn = BufferedReader(InputStreamReader(clientSocket.getInputStream(), "UTF-8")) //socketOut = PrintWriter(BufferedWriter(OutputStreamWriter(clientSocket.getOutputStream())),true) dis = DataInputStream(FileInputStream(tempfile)) dos = DataOutputStream(clientSocket.getOutputStream()) val buf = ByteArray(1024) var read_length : Int = 0 do { read_length = dis.read(buf) if(read_length == -1) break dos.write(buf) dos.flush() } while(read_length > 0) var line : String? var StringBuilder = StringBuilder() do { line = socketIn.readLine() if(line == null) break StringBuilder.append(line) }while(line != null) onApiResult(line) } catch (e : Exception){ Log.d("error", "${e}") onApiFailed() } finally { clientSocket.close() } this is my android client code. client send the image to python server using tcp. The image is sent well but the string does not come. There is an error here line = socketIn.readLine() please tell me how to fix it from socket import * serverPort = 8000 serverSocket = socket(AF_INET, SOCK_STREAM) serverSocket.bind(('123.234.345.456', serverPort)) serverSocket.listen(1) print('The server is ready to receive') msg = "hi" while True: connectionSocket, addr = serverSocket.accept() img_file = open('hi.jpg', "wb") while True: sentence = connectionSocket.recv(1024) data = sentence img_file.write(sentence) if sentence: print("recving IMg....") print(sentence) sentence = connectionSocket.recv(1024) img_file.write(sentence) else: print('Done') img_file.close() break connectionSocket.sendall(bytes(msg, 'UTF-8')) connectionSocket.close()
Just a guess -- you are sending binary data, but your client code uses java Reader/Writer classes (dedicated to reading text-like data). Use Streams, instead of Reader/Writer. There is no notion of 'endOfLine' when reading binary data. Also note, that client call to 'readLine()' assumes client platform dependent end-of-line, whatever it may be. If server and client platform differ, it will never work.
Frustating Error in python 3; TypeError: str, bytes or bytearray expected, not int
I am trying to make an application with python that allows users to connect to a server and chat with each other. The users have to enter a Host(IP) and port, then press a button to connect to a server. The buttons and boxes are done with tkinter. When I use a tkinter button to connect to a server It returns: TypeError: str, bytes or bytearray expected, not int Trying to connect with something like this works: HOST = input("Enter Host: ") The relevant code is as follows: #To connect to a server host def connect(): HOST = etyHost.get() PORT = etyPort.get() if isinstance(HOST, str) == True: print ("Yes") else: print ("NO") print(HOST, PORT) if not PORT: PORT = 33000 # Default value. else: PORT = int(PORT) client_socket.connect(ADDR) #Entry box etyHost = Entry(jahchat) etyHost.pack() etyHost.place(x = 0, y = 250) #Entry box etyPort = Entry(jahchat) etyPort.pack() etyPort.place(x = 0, y = 275) #Button btnConnect = Button(jahchat, text = "Connect", command = connect) btnConnect.config(width = 20) btnConnect.place(x = 0, y = 320) HOST = 1 PORT = 1 client_socket = socket(AF_INET, SOCK_STREAM) BUFSIZ = 1024 ADDR = (HOST, PORT) I have tried using str() to convert the port and Ip integers to strings. Python recognizes it as a string but the issue is not resolved. All answers are appreciated.
You must first convert the string that contains the IP address into a byte or a string of bytes and then start communicating. According to the code below, your error will be resolved. Make sure your code is working correctly overall. string = '192.168.1.102' new_string = bytearray(string,"ascii") ip_receiver = new_string s.sendto(text.encode(), (ip_receiver, 5252))
The raw sockets can't create an ARP request packet with source (MAC and IP )taken as some other machine .. Any suggestions?
I'm using the below script for injecting an ARP packet request. When I keep the source (MAC and IP) as my machine, I can happily see the packets in the wire and receive ARP replies however on changing the source to a different machine in the LAN, the ARP requests don't get back the ARP replies. I am dicey if the RAW sockets can only frame up an ARP request for the base machine or am I going wrong somewhere ? Below is the code ... #!/usr/bin/python import sys import socket import binascii import struct from itertools import chain try: iFace = raw_input("Enter the interface using which the Injection needs to be done ...\n") rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW,socket.htons(0x0800)) rawSocket.bind((iFace, socket.htons(0x0800))) print "Raw Socket got created .... with the Ethernet Protocol Id : 0x0806 at interface %s"%str(iFace) except: print "Something unexpected happened during the Program execution." else: def checkMac(mac): if len(mac.split(":")) != 6: print "The MAC is in correct. It should be in Hexadecimal Format with each byte separated with colon...\n" sys.exit(0) else: macList = mac.split(":") macLen = len(macList) return tuple ([int(macList[index],16) for index in range(macLen)]) def checkIp(ip): ipList = ip.split(".") ipLen = len(ipList) return int( "".join( [ "{:02X}".format(int(ele)) for ele in ipList ] ), 16 ) dMac = raw_input("Enter the Destination MAC .. hexadecimal charaters separated with ':' \n") # dMac = "0X:XX:XX:XX:XX:4X" dMacTup = checkMac(dMac) # sMac = raw_input("Enter the Source MAC .. hexadecimal charaters separated with ':' \n") sMac = "XX:XX:XX:XX:XX:XX" sMacTup = checkMac(sMac) type = 0x0806 # Creating an Ethernet Packet .... using dMac, sMac, type etherPack = struct.pack ("!6B6BH",*tuple(chain(dMacTup,sMacTup,[type]))) # Creating an ARP Packet .... now hardwareType = 0x0001 protocolType = 0x0800 hln = 0x06 pln = 0x04 op = 0x0001 # srcIp = raw_input("Enter the Source IP ':' \n") srcIp = "10.0.2.216" intSrcIp = checkIp(srcIp) destIp = raw_input("Enter the Destination IP .. \n") # destIp = "10.0.2.1" intDestIp = checkIp(destIp) arpPack = struct.pack("!HHBBH6BI6BI", *tuple(chain( [hardwareType,protocolType,hln,pln,op], sMacTup,[intSrcIp], dMacTup,[intDestIp] ))) # Framing the final Packet finalPack = etherPack + arpPack for i in range(50): rawSocket.send(finalPack + "Hacker in the wires ...") print "Sending Packet %d"%i finally: print "Closing the created Raw Socket ..." rawSocket.close()
How do I recover from a serialException using pySerial
I have an application that reads and transmits data to a device connected via USB. I'm using pySerial to facilitate this communication. Everything works fine until the USB cable is unplugged from the PC and an exception is thrown. Once the cable is plugged back in, I can't seem to recover and reconnect to my device. The only way for me to recover is to close down the application and unplug and plug the cable in again. Any help in understanding what's going on would be much appreciated. This is basic test code that I'm useing to help me understand the process. # Class used to communicate with USB Dongle import serial import time import sys class LPort: def __init__(self, port=0): "initialize the LPort class" self.error = "" self.traffic = "" self.dest = None if port == None: self.simulation = True else: self.simulation = False self.port = port # serial port we should use self.reset() self.time = time.time() def reInit(self): self.close() def reset(self): "flush port, reset the LPort, initialize LPort" if self.simulation: r = "LPort simulator" else: self.port.flushInput() self.port.flushOutput() self.fail = False self.command("/H1") self.dest = None r = "reset" self.error = "" self.traffic = "" return r def status(self): "return accumulated status info, reset collection" s = self.error self.error = "" return s def data(self): "return accumulated traffic data, reset collection" s = self.traffic self.traffic = "" return s def set_dest(self, addr): "set the destination address (if necessary)" if addr != self.dest: self.dest = addr self.command("/O") r = self.command("/D%02X" % addr) if r != "*": self.dest = None self.error += r else: r = True return r def checksum(self, bytes): "calculate the CRC-8 checksum for the given packet" crc_table = [ # this table is taken from the CP rectifier code 0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F, 0x36,0x31,0x24,0x23,0x2A,0x2D,0x70,0x77,0x7E,0x79, 0x6C,0x6B,0x62,0x65,0x48,0x4F,0x46,0x41,0x54,0x53, 0x5A,0x5D,0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5, 0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD,0x90,0x97, 0x9E,0x99,0x8C,0x8B,0x82,0x85,0xA8,0xAF,0xA6,0xA1, 0xB4,0xB3,0xBA,0xBD,0xC7,0xC0,0xC9,0xCE,0xDB,0xDC, 0xD5,0xD2,0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA, 0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2,0x8F,0x88, 0x81,0x86,0x93,0x94,0x9D,0x9A,0x27,0x20,0x29,0x2E, 0x3B,0x3C,0x35,0x32,0x1F,0x18,0x11,0x16,0x03,0x04, 0x0D,0x0A,0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42, 0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A,0x89,0x8E, 0x87,0x80,0x95,0x92,0x9B,0x9C,0xB1,0xB6,0xBF,0xB8, 0xAD,0xAA,0xA3,0xA4,0xF9,0xFE,0xF7,0xF0,0xE5,0xE2, 0xEB,0xEC,0xC1,0xC6,0xCF,0xC8,0xDD,0xDA,0xD3,0xD4, 0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C,0x51,0x56, 0x5F,0x58,0x4D,0x4A,0x43,0x44,0x19,0x1E,0x17,0x10, 0x05,0x02,0x0B,0x0C,0x21,0x26,0x2F,0x28,0x3D,0x3A, 0x33,0x34,0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B, 0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63,0x3E,0x39, 0x30,0x37,0x22,0x25,0x2C,0x2B,0x06,0x01,0x08,0x0F, 0x1A,0x1D,0x14,0x13,0xAE,0xA9,0xA0,0xA7,0xB2,0xB5, 0xBC,0xBB,0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83, 0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB,0xE6,0xE1, 0xE8,0xEF,0xFA,0xFD,0xF4,0xF3] for i in range(len(bytes)): b = int(bytes[i]) if i == 0: chksum = crc_table[b] else: chksum = crc_table[chksum ^ b] return chksum def command(self, cmd): "transmit distinct commands to unit, and accept response" if self.simulation: r = "*" else: try: self.port.write(cmd + chr(13)) except serial.serialutil.SerialTimeoutException: r = "/TO" return r except: print "Unexpected error:", sys.exc_info()[0] r = "/Unknown" return r r = "" eol = False while True: c = self.port.read(1) if not c: r = "/FAIL " + r + " " + cmd self.error = r break else: r += c ordc = ord(c) if ordc == 13 or ordc == 42: break return r def checkRawDataForErrors(self, raw, errors = []): errorCodes = {'/SNA':'Slave Not Acknowledging', '/I81':'Busy, Command Ignored', '/I88':'Connection Not Open', '/I89':'Invalid Command Argument', '/I8A':'Transmit Not Active', '/I8F':'Invalid Command', '/I90':'Buffer Overflow', '/DAT':'Data Error', '/BADPEC':'Bad PEC Value', '/NO_MRC':'No Master Read Complete Signal', '/FAIL':'General Failure', '/LEN':'Data Length Error'} for ekey, eval in errorCodes.items(): if ekey in raw: errors.append(eval) return errors # self-testing module if __name__ == "__main__": com = serial.Serial(port=4, baudrate=115200, timeout=1, xonxoff=0) if com: port = LPort(com) print port time.sleep(5) port = LPort(com) print "/V =", port.command("/V") print "/V", port.data(), port.status() print "/O =", port.command("/O") print "/O", port.data(), port.status() print "/A =", port.command("/A") print "/A", port.data(), port.status() print "/L =", port.command("/L") print "/L", port.data(), port.status() com.close() else: print "cannot open com port" UPDATE: The following is the code around the creatfile() in serialwin32.py which returns the following message: serial.serialutil.SerialException: could not open port COM5: [Error 2] The system cannot find the file specified. self.hComPort = win32.CreateFile(port, win32.GENERIC_READ | win32.GENERIC_WRITE, 0, # exclusive access None, # no security win32.OPEN_EXISTING, win32.FILE_ATTRIBUTE_NORMAL | win32.FILE_FLAG_OVERLAPPED, 0) if self.hComPort == win32.INVALID_HANDLE_VALUE: self.hComPort = None # 'cause __del__ is called anyway raise SerialException("could not open port %s: %s" % (self.portstr, ctypes.WinError()))
Assuming your device is well-behaved, all you must do is this: close your serial port (serial.Serial instance) find the COMX name of your port again open the serial port The 2nd part is problematic because Windows tries to be clever. In your case the following happens: USB device is connected and is assigned name COM2 Your program opens the device USB disconnects USB reconnects quickly before your program noticed that device died Windows sees that COM2 is busy and assigns a different name to this USB device (optional) your program closes the device your program tries to open COM2 again, but there's no hardware at that name The are way to get around Windows being clever -- you can specifically assign fixed COMX name to this device in Device Manager, COM ports, your port, advanced options. Another option is to detect device dying very fast and closing the file handle. If you are lucky then by the time device reconnects original COM2 is free again. Yet another option is to use a USB-serial converter from another manufacturer that uses another driver. Somehow COMX letter assignment is driver-specific. Better drivers may give you a stable name.
I've come across this problem as well. Sometimes my program has locked up when the device is plugged in again. NB. I have fixed the COMx name of the port as mentioned by #qarma I've rearranged my program so that as soon as an exception is thrown from the read() or write() methods of Serial I stop calling those methods. I then have a function which periodically retries opening the port to try to detect when the device has been plugged in again. This function creates a new instance of Serial with the same parameters as the original and tries to open it: def try_to_open_new_port(self): ret = False test = serial.Serial(baudrate=9600, timeout=0, writeTimeout=0) test.port = self.current_port_name try: test.open() if test.isOpen(): test.close() ret = True except serial.serialutil.SerialException: pass return ret A return of True indicates that the port is present once again.