Python: Binding a socket to /dev/rfcommX - python

I have a script that loads a Firmware on an embedded device over a serial port. The script takes the /dev/xxx adress of the serial port as an argument.
I have a special setup, where I do this over Bluetooth.
I managed to connect via bluetooth to the module in python. However I just can't find any example/information on how to register the local socket in a serial device like /dev/rfcomm0.
####### ORCA Bluetooth uploader Script #######
#As an input argument the script needs the BT Adress of the racer.
#if none is given, the script looks for nearby devices.
import bluetooth
import subprocess
import sys
import os
#Check if we received a BT ADDR
if sys.argv[-1] != 'bt_comm.py':
#Define the Pin for binding and the connection Port
#Our Pin is 0000
pin = "0000"
#The Bootoader is listening on Port 1 for a connection
port = 1
rfcomm_port = 0
#The BT Addr we get from the command line input
#TAG:TODO:Check the input for sanity
addr = sys.argv[-1]
#Build the Firmware image
subprocess.call("python ./px_mkfw.py --image ../../Firmware_orca/Images/px4fmu.bin > orca_fw",shell=True)
#Create an RFCOMM Socket
server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
#Connect to the device
server_sock.connect((addr, port))
print "Connected to ",addr
Here I need some way to register server_sock at /dev/rfcomm0
#Call the px_uploader script
subprocess.call("python ./px_uploader.py --port /dev/rfcomm%d orca_fw" % rfcomm_port,shell=True)
#Close the connection
server_sock.close()
else:
#Look for BT Devices and print them
discovered_devices = bluetooth.discover_devices(lookup_names = True, flush_cache = True, duration = 20)
if discovered_devices is not None:
for addr in discovered_devices:
print "Found bluetooth device: ", addr
else:
print "Could not find any bluetooth device nearby"

Related

Recognition of a specific USB device in python

I am making app in python, that connects with Arduino. I want this app to work on different computers, when arduino is connected to any port. I was trying to do a function that checks to which port is arduino connected to:
def arduinoConnect():
t=0
temp = 0;
while 1:
i = str(t)
try:
temp = serial.Serial('com'+i, 9600)
if temp:
print("COM" + i + " Connected")
break
except:
print("COM" + i + " Empty")
t = t + 1
if t == 41:
break
return temp
But this code only sees if anything is connected, so when i am also using some bluetooth devices, or other microcontrolers, it takes the device that is connected to the com port with the lowest number.
Next idea was to take PID and VID number:
import serial
import serial.tools.list_ports
for port in serial.tools.list_ports.comports():
print(port.hwid)
But i have one more device connected to COM Port, that gives exactly the same numbers, only different location:
USB VID:PID=1A86:7523 SER= LOCATION=1-4
USB VID:PID=1A86:7523 SER= LOCATION=1-5
I also tried to get a specific id of a connected USB device:
import serial
def serial_ports():
ports = ['COM%s' % (i + 1) for i in range(256)]
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
print(s)
except (OSError, serial.SerialException):
pass
return result
if __name__ == '__main__':
print(serial_ports())
And it returns the ID of a device, which is unique to every device, but changes every time i disconnect and connect again the device.
My question is how to let my code recognize and connect one and only device I want? On any computer, connected to any port.
I understand your problem as such that you wish to have python code that can connect to an arduino device which is connected to any port, on any computer.
So the solution is to uniquely identify the arduino device even when other devices are plugged in.
It should work when you get the device serial number:
import serial
import serial.tools.list_ports
def get_arduino_serial_number():
for port in serial.tools.list_ports.comports():
if 'Arduino' in port.description:
return port.serial_number
return None
whether this works or not is dependent on port.description.
Change USB COM port description
Get ports by description
With the serial number of the Arduino device, you can then connect to it using:
ser = serial.Serial(port='COMx', baudrate=9600, timeout=1,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS)
Opening serial ports | pySerial

How to setup a raspberry pi as server and client at the same time?

I am using my Raspberry as a server and client at the same time.
However, my RPI don't enable the connection as server after it connecting to another device as a client. The requirement is, the RPI has to connect to several devices at once.
The minimal example with ethernet cable would be:
Device A <-----ETH-----> RPI <-----ETH-----> Device B
So in the above configuration, first connecting it to Device B as a client, Device A can not be connected to the RPI. If I use it as a standalone server/client it works perfectly but as parallel functionality it doesnt work. There is no error message, Device A just doesnt connect to the Raspberry.
Note that, I am connecting device A via Ethernet-to-USB adapter and it works perfectly as standalone server. I am using multiprocessing for each device on the raspberry.
Any help is appreciated.
I note that in that configuration the raspberry acts as access point (?).
The functionality of the raspberry is, that it has to forward the incoming messages to another device, so that each device doesn't know the port or IP address of each other, only the PI does.
So my simplified code for the raspberry is:
walkie_talkie.py
import socket
# socket.socket(socket.AF_INET, socket.SOCK_STREAM)
class walkie_talkie(socket.socket):
'''Inherits all functionalities of sockets.sockets
Use this class for connection using TCP/IP e.g. internet/ethernet
Example usage:
>>> from walkie_talkie import walkie_talkie
>>> wt = walkie_talkie()
>>> wt.BUFFERSIZE = 8
...
'''
def __init__(self):
self.BUFFERSIZE = 8192
self.STATE = None
self.IP = None # Server IP
self.PORT = 5000
self.NUMBER_OF_UNACCEPTED_CONNECTIONS = 1
self.bytestream = None
self.PROTOCOL = socket.SOCK_STREAM # Using UDP: socket.SOCK_DGRAM
super().__init__(socket.AF_INET, self.PROTOCOL)
def setup_server(self):
print('****** SERVER SETUP ******\n'
'TCP/IP: {}\n'
'PORT: {}\n'
'BUFFERSIZE: {}\n'
'Acc. conn.: {}\n'
'****** SERVER SETUP ******\n'.format(self.IP,
self.PORT,
self.BUFFERSIZE,
self.NUMBER_OF_UNACCEPTED_CONNECTIONS))
self.STATE = 'SERVER'
self.bind((self.IP, self.PORT))
self.listen(self.NUMBER_OF_UNACCEPTED_CONNECTIONS)
self.CONN, self.ADDRESS = self.accept()
def setup_client(self):
print('****** CLIENT SETUP ******\n'
'TCP/IP: {}\n'
'PORT: {}\n'
'BUFFERSIZE: {}\n'
'Acc. conn.: {}\n'
'****** CLIENT SETUP ******\n'.format(self.IP,
self.PORT,
self.BUFFERSIZE,
self.NUMBER_OF_UNACCEPTED_CONNECTIONS))
self.STATE = 'CLIENT'
#self.settimeout(10.0)
self.connect((self.IP, self.PORT))
#self.settimeout(None)
print('Connected.')
Since I also have to stream the data through multiple ports of the same devices, I am using multiprocessing for each communication tunnel.
multiprocessing_rpi.py
import socket
from walkie_talkie import walkie_talkie
import multiprocessing
import time
def setup_alpha_watchdog(IP, PORT):
''' Creates an alpha watchdog
:param str IP: Server IP on Raspberry to listen to
:param int PORT: Server Port to open for Device A
'''
global BUFFERSIZE
print('alpha Watchdog >> {} # {}'.format(IP, PORT))
alpha_watchdog = walkie_talkie()
alpha_watchdog.IP = IP
alpha_watchdog.PORT = PORT
alpha_watchdog.BUFFERSIZE = BUFFERSIZE
try:
# Setup alpha watchdog and omega watchdog right afterwards
alpha_watchdog.setup_server()
omega_watchdog = setup_omega_watchdog(DEVICE_B_IP, PORT) # returns a walkie_talkie object as client
superstream(alpha=alpha_watchdog,
omega=omega_watchdog)
except Exception as watchdog_error:
print('Error: ' + str(watchdog_error))
exit()
pass
def setup_omega_watchdog(IP, PORT):
''' Creates an omega watchdog
Description:
omega watchdog takes data from alpha watchdog and pass them to the specified device
If the connection is denied, abort both watchdogs.
:param str IP: Server IP of Device B to connect to
:param int PORT: Server Port on Device B to send data to
'''
global BUFFERSIZE
print('omega Watchdog >> {} # {}'.format(IP, PORT))
watchdog = walkie_talkie()
watchdog.IP = IP
watchdog.PORT = PORT
watchdog.BUFFERSIZE = BUFFERSIZE
try:
watchdog.setup_client()
except Exception as watchdog_error:
print('Error: ' + str(watchdog_error))
exit()
return watchdog
def superstream(alpha, omega):
'''Streams data between the watchdogs on Request-Response scheme
Description:
After setting alpha & omega watchdogs, the communication takes place after incoming signal from alpha passed to omega.
For example, the byte b'\x02\x00\x00\x00\xff\x00' coming from Device A will be passed to alpha watchdog
and the raspberry will then pass this byte to the omega watchdog and finally to the Device B.
:param object alpha: An alpha watchdog
:param object omega: An omega watchdog
'''
while 1:
try:
# Get data coming from Device A and send it directly to Device B
data_from_Device_A = alpha.CONN.recv(alpha.BUFFERSIZE)
omega.send(data_from_Device_A )
# Get response from Device B and send back to Device A
RESPONSE= omega.recv(omega.BUFFERSIZE)
alpha.CONN.send(RESPONSE)
except Exception as e1:
print('Error: ' + str(e1))
break
alpha.shutdown(2)
alpha.close()
omega.shutdown(2)
omega.close()
if __name__ == '__main__':
THIS_RPI_IP= '169.254.244.192' # IP of raspberry, so Device A can connect to it
DEVICE_B_IP = '192.xxx.....' # Device B IP
# Reserve ports correlating number of devices
SERVER_PORTS = [5000,
# 5001,
# 5002,
# 5003,
# 5004,
5005]
SERVER_IP = THIS_RPI_IP
BUFFERSIZE = 8192
PROCESS_LIST = []
#For each port, setup a socket for clients
for PORT in SERVER_PORTS:
p = multiprocessing.Process(target=setup_alpha_watchdog, args=(THIS_RPI_IP, PORT,))
PROCESS_LIST.append(p)
p.start()
for _ in PROCESS_LIST:
_.join()
In setup_alpha_watchdog I can swap the line, where I first connect as client to device B (Successfully!) and then listen to device A, however I am not able to establish a connection as server to device A.

Python socket issue when connecting to raspberry pi

I am trying to do wireless communications between a PC (windows) and a Raspberry Pi 3 using python's socket module. The server is the PC and the client is the Pi. When I run the code (server first then client) both scripts get stuck after "hey, checking TCP socket".
When I do the reverse (Pi being the server and PC being the client) the code works fine, with data been sent correctly.
Both the PC and Pi are connected to the same network. The IP address of PC is 10.0.0.198 and the Pi is 10.0.0.63.
I think the problem is that the port is not open when I use my PC as a server. How to resolve this?
My client script:
import socket
import sys
def read(port):
s = socket.socket()
host = '10.0.0.198' #(IP address of PC (server))
s.connect((host,port))
try:
msg = s.recv(1024)
s.close()
except socket.error, msg:
sys.stderr.write('error %s'%msg[1])
s.close()
print 'close'
sys.exit(2)
return msg
if __name__ == '__main__':
port = 1025
while True:
print 'hey, checking TCP socket'
data = read(port)
print 'i just read %s' % data
print 'port num is: %d' % port
port = port + 1
My server script:
import socket
import time
def send(data, port):
s = socket.socket()
s.bind(('', port))
s.listen(5)
c, addr = s.accept()
print 'Got connection from',addr
c.send(data)
c.close()
if __name__ == '__main__':
port = 1025
num = 1
while True:
print 'hey, sending data'
words = 'helloWorld'
data = words + str(num)
print 'send data: %s' % data
send(data,port)
port = port + 1
num = num + 1

How to add logging to a file with timestamps to a Python TCP Server for Raspberry Pi

I am kinda stuck for my project & I desperately need help. I need a simple TCP server python code that has features like logging & time stamp which I could use for my Raspberry Pi. Its for my Final Year Project.
I've looked at some examples, but as I don't have much experience in writing my own scripts/codes, I'm not very sure how to go about doing this. I would appreciate if someone could guide me in the right direction with explanation and some examples if possible.
I am using HERCULES SETUP UTILITY , which acts as my TCP client, while my visual studio python code acts as a SERVER. My SERVER can receive the data which is sent by the client by now , I just can't seem to add in a logging file which can save the sent data into text file.Can someone please show me some examples or referance please? Your help would mean alot. This is my code so far :
from socket import *
import thread
BUFF = 1024 # buffer size
HOST = '172.16.166.206'# IP address of host
PORT = 1234 # Port number for client & server to recieve data
def response(key):
return 'Sent by client'
def handler(clientsock,addr):
while 1:
data = clientsock.recv(BUFF) # receive data(buffer).
print 'data:' + repr(data) #Server to recieve data sent by client.
if not data: break #If connection is closed by client, server will break and stop recieving data.
print 'sent:' + repr(response('')) # respond by saying "Sent By Client".
if __name__=='__main__':
ADDR = (HOST, PORT) #Define Addr
serversock = socket(AF_INET, SOCK_STREAM)
serversock.bind(ADDR) #Binds the ServerSocket to a specific address (IP address and port number)
serversock.listen(0)
while 1:
print 'waiting for connection...'
clientsock, addr = serversock.accept()
print '...connected from:', addr #show its connected to which addr
thread.start_new_thread(handler, (clientsock, addr ))
To add logging to a file with timestamps, you could use logging module:
import logging
logging.basicConfig(level=logging.INFO,
filename='myserver.log', # log to this file
format='%(asctime)s %(message)s') # include timestamp
logging.info("some message")
If you run the code; you should see in myserver.log (+/- your timezone and current time):
2013-12-24 09:20:17,739 some message
Here's a complete example of TCP server that prepends each received line from a client with "Sent by Client: " phrase and sends it back:
#!/usr/bin/env python
import logging
import sys
from SocketServer import ThreadingTCPServer, StreamRequestHandler
info = logging.getLogger(__name__).info
class EchoLineHandler(StreamRequestHandler):
def handle(self):
info("handling request from %s", self.client_address)
# prepend each line (b'\n') and send it back
for line in self.rfile:
self.wfile.write(b"Sent by Client: ") # assume ascii-based encoding
self.wfile.write(line)
info("done %s", self.client_address)
def test(ServerClass=ThreadingTCPServer, HandlerClass=EchoLineHandler):
# configure logging
logging.basicConfig(level=logging.INFO,
filename='server.log', # log to this file
format='%(asctime)s %(message)s') # include timestamp
# parse command line arguments
host, port = 'localhost', 8826
if len(sys.argv) > 1:
host_, separator, port_ = sys.argv[1].rpartition(":")
port = int(port_)
if separator: # if ":" in sys.argv[1]
host = host_ # accept any host, including empty
# listen for connections
server = ServerClass((host, port), HandlerClass)
info("Serving on %s port %s", *server.server_address)
try:
server.serve_forever()
finally:
info("quit.")
if __name__=="__main__":
test()
To run the server if the code is save in echo_line_server.py:
$ python -mecho_line_server localhost:8826 & tail -F server.log
2013-12-24 17:09:38,089 Serving on 127.0.0.1 port 8826
To run a client:
$ echo abc | nc localhost 8826
Sent by Client: abc

RFCOMM without pairing using PyBluez on Debian?

I am trying to create an RFCOMM server process with Python that can be used without the need for pairing. Initially, I grabbed the two example scripts from the PyBluez documentation:
Server:
# file: rfcomm-server.py
# auth: Albert Huang <albert#csail.mit.edu>
# desc: simple demonstration of a server application that uses RFCOMM sockets
#
# $Id: rfcomm-server.py 518 2007-08-10 07:20:07Z albert $
from bluetooth import *
server_sock=BluetoothSocket( RFCOMM )
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port = server_sock.getsockname()[1]
uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
advertise_service( server_sock, "SampleServer",
service_id = uuid,
service_classes = [ uuid, SERIAL_PORT_CLASS ],
profiles = [ SERIAL_PORT_PROFILE ],
# protocols = [ OBEX_UUID ]
)
print "Waiting for connection on RFCOMM channel %d" % port
client_sock, client_info = server_sock.accept()
print "Accepted connection from ", client_info
try:
while True:
data = client_sock.recv(1024)
if len(data) == 0: break
print "received [%s]" % data
except IOError:
pass
print "disconnected"
client_sock.close()
server_sock.close()
print "all done"
Client:
# file: rfcomm-client.py
# auth: Albert Huang <albert#csail.mit.edu>
# desc: simple demonstration of a client application that uses RFCOMM sockets
# intended for use with rfcomm-server
#
# $Id: rfcomm-client.py 424 2006-08-24 03:35:54Z albert $
from bluetooth import *
import sys
addr = None
if len(sys.argv) < 2:
print "no device specified. Searching all nearby bluetooth devices for"
print "the SampleServer service"
else:
addr = sys.argv[1]
print "Searching for SampleServer on %s" % addr
# search for the SampleServer service
uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
service_matches = find_service( uuid = uuid, address = addr )
if len(service_matches) == 0:
print "couldn't find the SampleServer service =("
sys.exit(0)
first_match = service_matches[0]
port = first_match["port"]
name = first_match["name"]
host = first_match["host"]
print "connecting to \"%s\" on %s" % (name, host)
# Create the client socket
sock=BluetoothSocket( RFCOMM )
sock.connect((host, port))
print "connected. type stuff"
while True:
data = raw_input()
if len(data) == 0: break
sock.send(data)
sock.close()
When I ran the server script on Windows everything worked just how I had hoped - no pairing was necessary. At this stage everything was looking very promising.
However, I need the server process to run under Debian Squeeze. When I test on Debian the client connection is refused. In the syslog there are messages from bluetoothd for a failed link key request and PIN request.
Version information:
PyBluez 0.18
Python 2.6
Bluez 4.66
Bluetooth v2.0 hardware on both ends of the connection
This discussion seems to suggest that if I can adjust the security level on the server socket then pairing will be disabled and everything will just work as expected. It is not apparent to me how to do this with PyBluez though, or even if it is possible.
I have experimented with calls to setsockopt() using various BT_SECURITY* constants, as well as grabbing the last PyBluez and calling setl2capsecurity() but have not been able to make any progress.
Is this going to be achievable with PyBluez?
This turned out to be a problem with the Debian Squeeze bluez default configuration.
If anyone else hits this problem, disable the pnat plugin by editing /etc/bluetooth/main.conf:
DisablePlugins = pnat
Then restart bluetoothd.
$ sudo invoke-rc.d bluetooth restart
No changes were required to the PyBluez code.

Categories

Resources