Python PyBluez connecting to passkey protected device - python

I'm working on an application in Python (currently 2.7, can switch to 3.3 if necessary) that is supposed to:
Detect bluetooth device (finger clip pulse oximeter, if you're interested).
Establish connection with device (which is passkey protected)
Stream data from the device to my computer
Do more (currenly irrelevant) programming with the data
To accomplish this, I'm using the PyBluez library for Python, as it is probably the most documented library I've found (which sadly is still quite little) that is compatible with Windows and Python2.7.
I am very new to socket programming, so this is probably a simple question. The issue I've encountered, is that I cannot seem to figure out how to connect to the device since it is passkey protected. I can locate it and retrieve its address with no problem, I just don't know what port to use when connecting or how to enter a passkey.
Thanks for your help!
Reference Information:
Pulse oximeter used: http://www.echostore.com/wireless-oximeter-cms50e.html
PyBluez library: http://pybluez.googlecode.com/svn/www/docs-0.7/index.html

I meet the same problem,and I have resolved the problem, Maybe you can try it:
make a windows tool named pairtool.exe, it help you to pairing with command line.
dwRet = BluetoothAuthenticateDevice(NULL, NULL, &btdi, L"1234", 4);
if(dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
ExitProcess(2);
}
python code:
def connect2Btdev(devName):
#found the device addr
addr = inquiry(devName)
if addr == None:
return None
#pairing with pairtool.exe
cmd=r'%s %s' % ('pairtool.exe',addr)
ret = os.system(cmd)
if ret <> 0:
return None

PyBlueZ does not expose the windows Bluetooth authentication APIs here: https://msdn.microsoft.com/en-us/library/windows/desktop/cc766819(v=vs.85).aspx
One way to get around this is to create a command line tool and use this through Python. To create command line tools for Windows, use Visual Studio and add the necessary libraries to your project linker properties: Bthprops.lib and ws2_32.lib
Below is the code for a project to make a command line tool with 1 parameter, the MAC address, that pairs the specified device using "Just Works" pairing. See commented code for using passkey pairing.
#include "stdafx.h"
#include <initguid.h>
#include <winsock2.h>
#include <BluetoothAPIs.h>
#include <ws2bth.h>
BOOL WINAPI BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams);
int _tmain(int argc, _TCHAR* argv[])
{
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
DWORD dwRet;
BLUETOOTH_DEVICE_INFO btdi = { 0 };
HBLUETOOTH_AUTHENTICATION_REGISTRATION hRegHandle = 0;
// initialize windows sockets
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 0);
if (WSAStartup(wVersionRequested, &wsaData) != 0) {
ExitProcess(2);
}
// parse the specified Bluetooth address
if (argc < 2) {
fprintf(stderr, "usage: csbtpair <addr>\n"
"\n addr must be in the form (XX:XX:XX:XX:XX:XX)");
ExitProcess(2);
}
if (SOCKET_ERROR == WSAStringToAddress(argv[1], AF_BTH,
NULL, (LPSOCKADDR)&sa, &sa_len)) {
ExitProcess(2);
}
// setup device info
btdi.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
btdi.Address.ullLong = sa.btAddr;
btdi.ulClassofDevice = 0;
btdi.fConnected = false;
btdi.fRemembered = false;
btdi.fAuthenticated = false;
// register authentication callback. this prevents UI from showing up.
dwRet = BluetoothRegisterForAuthenticationEx(&btdi, &hRegHandle, &BluetoothAuthCallback, NULL);
if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothRegisterForAuthenticationEx ret %d\n", dwRet);
ExitProcess(2);
}
// authenticate device (will call authentication callback)
AUTHENTICATION_REQUIREMENTS authreqs = MITMProtectionNotRequired;
fprintf(stderr, "BluetoothAuthReqs = %d\n", authreqs);
dwRet = BluetoothAuthenticateDeviceEx(NULL, NULL, &btdi, NULL, authreqs);
if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
if (dwRet == ERROR_CANCELLED)
{
fprintf(stderr, "Cancelled");
}
else if (dwRet == ERROR_INVALID_PARAMETER)
{
fprintf(stderr, "Invalid Parameter");
}
else if (dwRet == ERROR_NO_MORE_ITEMS)
{
fprintf(stderr, "Already paired!");
}
}
fprintf(stderr, "pairing finish\n");
ExitProcess(0);
return 0;
}
// Authentication callback
BOOL WINAPI BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams)
{
DWORD dwRet;
fprintf(stderr, "BluetoothAuthCallback 0x%x\n", pAuthCallbackParams->deviceInfo.Address.ullLong);
BLUETOOTH_AUTHENTICATE_RESPONSE AuthRes;
AuthRes.authMethod = pAuthCallbackParams->authenticationMethod;
fprintf(stderr, "Authmethod %d\n", AuthRes.authMethod);
// Check to make sure we are using numeric comparison (Just Works)
if (AuthRes.authMethod == BLUETOOTH_AUTHENTICATION_METHOD_NUMERIC_COMPARISON)
{
fprintf(stderr, "Numeric Comparison supported\n");
}
AuthRes.bthAddressRemote = pAuthCallbackParams->deviceInfo.Address;
AuthRes.negativeResponse = FALSE;
// Commented out code is used for pairing using the BLUETOOTH_AUTHENTICATION_METHOD_PASSKEY method
//memcpy_s(AuthRes.pinInfo.pin, sizeof(AuthRes.pinInfo.pin), L"1234", 0);
//AuthRes.pinInfo.pinLength = 0;
// Respond with numerical value for Just Works pairing
AuthRes.numericCompInfo.NumericValue = 1;
// Send authentication response to authenticate device
dwRet = BluetoothSendAuthenticationResponseEx(NULL, &AuthRes);
if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothSendAuthenticationResponseEx ret %d\n", dwRet);
if (dwRet == ERROR_CANCELLED)
{
fprintf(stderr, "Bluetooth device denied passkey response or communicatino problem.\n");
}
else if (dwRet == E_FAIL)
{
fprintf(stderr, "Device returned a failure code during authentication.\n");
}
else if (dwRet == 1244)
{
fprintf(stderr, "Not authenticated\n");
}
}
else
{
fprintf(stderr, "BluetoothAuthCallback finish\n");
}
return 1; // This value is ignored
}
In lieu of creating this yourself, you may want to try this pre-made solution:
http://bluetoothinstaller.com/bluetooth-command-line-tools/
It did not work for my particular solution.
Then, you will need to run your downloaded or custom command line tool from python as an administrator. To do this reliably, I recommend the stackoverflow question:
How to run python script with elevated privilege on windows

Related

C++ serial communication write speed

I'm using uPyCraft IDE and Putty For communicating with serial "COM3" Port.
and I make a new C++ console Application for using serial port now.
but C++ console application's running speed is slower than Pychon.
How can I improve performance? is my code is something wrong?
this is what I tried in C++
int serialib::writeBytes(const void *Buffer, const unsigned int NbBytes)
{
DWORD dwBytesWritten;
if(!WriteFile(hSerial, Buffer, NbBytes, &dwBytesWritten, NULL))
return -1;
return 1;
}
void writedata(const char * arg)
{
string result = arg;
serial.writeBytes(&result,sizeof(result));
}
int main()
{
serial.openDevice("COM3", 115200);
if (serial.isDeviceOpen() != true)
{
return 1;
}
for (int i = 1;i <= 1000;i++)
{
writedata("km.move(0,1) ");
}
}
this is what I tried in Putty or uPyCraft
for i in range(1000) : km.move(0,1)
I couldn't find what point did I wrong
Speed is different more than double.
Putty and uPyCraft is Faster than C++ console
I don't know is writedata function causing delay
What is the best code for at C++ Console, writeBytes to commuinating with serial?
p.s : BaudRate, ByteSize, Stopbits, Pariety is same
BaudRate : 115200
ByteSize : 8
StopBits : 1
Pariety : NONE (0)

Subscriber for ros2arduino publisher example?

I want to establish a WiFi-connection between an arduino
wifi-board and a computer with ROS2.
For the arduino-side I found the ros2arduino library,
which has some examples for publisher nodes.
Unfortunately I could not find the correponding
subscriber part for the subscriber.
Because I am new to ros2, I don't know
how to implement the corresponding subscriber.
My first idea to echo the publisher with this command:
ros2 topic echo /arduino_chatter
does not find the publisher. This is the error message:
WARNING: topic [/arduino_chatter] does not appear to be published yet
Could not determine the type for the passed topic
How has the subscriber to be implemented in ros2?
Thank you!
Here is the example code included in the
arduino library:
#include <ros2arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
#define SSID "xxx"
#define SSID_PW "yyy"
#define AGENT_IP "192.168.1.0"
#define AGENT_PORT 2018 //AGENT port number
#define PUBLISH_FREQUENCY 2 //hz
void publishString(std_msgs::String* msg, void* arg)
{
(void)(arg);
static int cnt = 0;
sprintf(msg->data, "Hello ros2arduino %d", cnt++);
}
class StringPub : public ros2::Node
{
public:
StringPub()
: Node("ros2arduino_pub_node")
{
ros2::Publisher<std_msgs::String>* publisher_ = this->createPublisher<std_msgs::String>("arduino_chatter");
this->createWallFreq(PUBLISH_FREQUENCY, (ros2::CallbackFunc)publishString, nullptr, publisher_);
}
};
WiFiClient client;
void setup()
{
WiFi.begin(SSID, SSID_PW);
while(WiFi.status() != WL_CONNECTED);
ros2::init(&client, AGENT_IP, AGENT_PORT);
}
void loop()
{
static StringPub StringNode;
ros2::spin(&StringNode);
}

Python server and java client not working properly

I want to make a socket between Java client
`
import java.util.*;
import java.net.*;
import java.io.*;
public class Main
{
public static void client()
{
final int port = 2003;
final String host = "localhost";
try
{
Socket soc = new Socket(host, port);
if(soc.isBound()){
System.out.println("socket binded");
}else if(soc.isConnected()){
Scanner in = new Scanner(soc.getInputStream());
System.out.println("enter msg");
String x = in.nextLine();
PrintStream p = new PrintStream(soc.getOutputStream());
p.println("#client" + x);
} else if(soc.isClosed()){
System.out.println("Closed tunnel");
System.exit(0);
soc.close();
}
}
catch (Exception e)
{
}
}
public static void main(String[] args)
{
client();
}
}
`
Its having problem allowing me to use the scanner to send msg to Python server{I dunno how to make this}
PS : am new and dunno how to make this snippets formatted

How can I set the file descriptors for a new Process in Haxe to use it with a socket?

I am translating some code to Haxe from Python so that I can target more platforms. But I'm having trouble with the following snippet.
import socket
from subprocess import Popen
host='127.0.0.1'
port=8080
file='handle.sh'
handler = socket.socket()
handler.bind((host, port))
handler.listen(5)
conn, address = handler.accept() # Wait for something to connect to the socket
proc = Popen(['bash', file], stdout=conn.makefile('wb'), stdin=conn.makefile('rb'))
proc.wait()
conn.shutdown(socket.SHUT_RDWR)
conn.close()
In Python, I can set stdin and stdout to the relevant file descriptors of the socket. But by the time I call shutdown, all the data to be sent is in the right buffer and nothing blocks me.
But I can't do this in Haxe as far as I can tell because input and output from the socket and, stdin and stdout from the process are all read-only.
I seem to get a deadlock with whatever I try. Currently I'm trying with a thread but it still gets stuck at reading from the socket.
#!/usr/bin/haxe --interp
import sys.net.Host;
import sys.net.Socket;
import sys.io.Process;
import sys.thread.Thread;
class HaxeServer {
static function main() {
var socket = new Socket();
var fname = 'handle.sh';
var host = '127.0.0.1';
var port = 8080;
socket.bind(new Host(host), port);
socket.listen(5);
while (true) {
var conn = socket.accept();
var proc = new Process('bash', [fname]);
exchange(conn, proc);
conn.output.write(proc.stdout.readAll());
proc.close();
conn.shutdown(true, true);
conn.close();
}
}
static function exchange(conn:Socket, proc:Process):Void {
#if (target.threaded)
Thread.create(() -> {
while (true) {
var drip = conn.input.readByte();
proc.stdin.writeByte(drip);
}
});
#end
}
}
Edit 1
Attempting to use the answer posted by #YellowAfterlife, I ran the following code instead of my exchange function.
conn.setBlocking(false);
Thread.create( () -> {
trace('--> read');
while (true) {
trace('-1a');
var data:Bytes = readAllNonBlocking(conn.input).bytes;
trace('-2a');
proc.stdin.write(data);
trace('-3a');
proc.stdin.flush();
}
});
trace('--> write');
while (true) {
trace('-1b');
var data:Bytes = readAllNonBlocking(proc.stdout).bytes;
trace('-2b');
conn.output.write(data);
trace('-3b');
conn.output.flush();
}
trace('Wait');
trace(proc.exitCode());
but it just logs this and hangs:
HaxeServer.hx:42: --> write
HaxeServer.hx:44: -1b
So it's not even getting into the thread and the input is still blocking.
If I put both read-write sections in threads, it just prints 'Wait'.
I have previously dealt (on a project bridging unrelated network APIs - GitHub repo) with the issue of reading all available data without deadlocking by marking the socket as non-blocking and implementing a custom function that reads all available data, like so:
public static function readAllNonBlocking(input:Input):{bytes:Bytes,eof:Bool} {
var total:BytesBuffer = new BytesBuffer();
var eof = false;
var len = 0;
try {
while (true) {
total.addByte(input.readByte());
len += 1;
}
} catch (x:Error) {
switch (x) {
case Blocked: // OK!
default: throw x;
}
} catch (x:Eof) {
eof = true;
}
var bytes:Bytes = total.getBytes();
if (bytes.length > len) {
bytes = bytes.sub(0, len);
}
return { bytes: bytes, eof: eof };
}
You will also likely need to .flush() stdin for data to actually make it to the process.

Connect a Metro app to a Python SSL server with a self-signed certificate

How can I use a StreamSocket in a Windows 8 Metro app to connect to a Python+OpenSSL-based server using a self-signed certificate in the server ? I've tried adding the server's public key to the various trusted stores on the Windows Desktop to no avail. Everything I've tried yields the same results: an exception with the same message as in this post.
I'm developing with Visual Studio 2013 on Windows 8.1, connecting to a Python 3.4 server running OpenSSL 1.0.1h
I was able to find the answer. Microsoft provides a sample here. Once you download the sample, check out scenario 5. Based on the code in that scenario, here's a Windows 8 App Store unit test class that provides an example of how to use the code:
namespace Services.Implementation.Tests
{
using System;
using System.Diagnostics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using Windows.Security.Cryptography.Certificates;
using System.Collections.Generic;
[TestClass]
public class NetworkConnectionIPv6Tests
{
#region Test Lifecycle Members
/// <summary>
/// Gets or sets the test context.
/// </summary>
/// <value>
/// The test context.
/// </value>
public TestContext TestContext
{
get; set;
}
#endregion // Test Lifecycle Members
#region Test Methods
[TestMethod, TestCategory("Integration")]
public void TestConnection()
{
const int ServerPort = 63253;
const string ServerIpAddress = "fe80::7ed1:c3ff:fed9:6fc7";
HostName hostName = new HostName(ServerIpAddress);
byte[] receiveBuffer = new byte[4096];
using (StreamSocket streamSocket = new StreamSocket())
{
bool retry = true;
do
{
try
{
streamSocket.ConnectAsync(hostName, ServerPort.ToString(), SocketProtectionLevel.Tls12).GetAwaiter().GetResult();
string certInformation = GetCertificateInformation(
streamSocket.Information.ServerCertificate,
streamSocket.Information.ServerIntermediateCertificates);
Debug.WriteLine("Certificate information: {0}", certInformation);
retry = false;
}
catch (Exception exception)
{
// If this is an unknown status it means that the error is fatal and retry will likely fail.
if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
// If the exception was caused by an SSL error that is ignorable we are going to prompt the user
// with an enumeration of the errors and ask for permission to ignore.
if (streamSocket.Information.ServerCertificateErrorSeverity != SocketSslErrorSeverity.Ignorable)
{
Debug.WriteLine("Connect failed with error: " + exception.Message);
Assert.Fail("Failed to avoid unignorable errors");
}
// ---------------------------------------------------------------------------
// WARNING: Only test applications may ignore SSL errors.
// In real applications, ignoring server certificate errors can lead to MITM
// attacks (while the connection is secure, the server is not authenticated).
// ---------------------------------------------------------------------------
streamSocket.Control.IgnorableServerCertificateErrors.Clear();
foreach (var ignorableError in streamSocket.Information.ServerCertificateErrors)
{
streamSocket.Control.IgnorableServerCertificateErrors.Add(ignorableError);
}
}
} while (retry);
byte[] messageBytes = Encoding.UTF8.GetBytes("Test");
Stopwatch stopwatch = Stopwatch.StartNew();
uint bytesSent = streamSocket.OutputStream.WriteAsync(messageBytes.AsBuffer()).GetAwaiter().GetResult();
Assert.AreEqual(messageBytes.Length, (int) bytesSent, "Failed to sent the correct amount of bytes");
IBuffer bytesReceived = streamSocket.InputStream.ReadAsync(receiveBuffer.AsBuffer(), (uint) receiveBuffer.Length, InputStreamOptions.None).GetAwaiter().GetResult();
stopwatch.Stop();
Debug.WriteLine("Remote call turnaround in {0} seconds", stopwatch.Elapsed.TotalSeconds);
Assert.IsTrue(bytesReceived.Length > 0, "There were no bytes received from the server");
string responseString = new string(Encoding.UTF8.GetChars(receiveBuffer, 0, (int) bytesReceived.Length));
Assert.AreEqual("Test right back", responseString, "Failed to receive the expected message from the server");
}
}
#endregion // Test Methods
#region Helper Methods
/// <summary>
/// Gets detailed certificate information
/// </summary>
/// <param name="serverCert">The server certificate</param>
/// <param name="intermediateCertificates">The server certificate chain</param>
/// <returns>A string containing certificate details</returns>
private string GetCertificateInformation(
Certificate serverCert,
IReadOnlyList<Certificate> intermediateCertificates)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("\tFriendly Name: " + serverCert.FriendlyName);
sb.AppendLine("\tSubject: " + serverCert.Subject);
sb.AppendLine("\tIssuer: " + serverCert.Issuer);
sb.AppendLine("\tValidity: " + serverCert.ValidFrom + " - " + serverCert.ValidTo);
// Enumerate the entire certificate chain.
if (intermediateCertificates.Count > 0)
{
sb.AppendLine("\tCertificate chain: ");
foreach (var cert in intermediateCertificates)
{
sb.AppendLine("\t\tIntermediate Certificate Subject: " + cert.Subject);
}
}
else
{
sb.AppendLine("\tNo certificates within the intermediate chain.");
}
return sb.ToString();
}
#endregion // Helper Methods
}
}
The key to using this example is that you have to be using Visual Studio 2013 targeting for Windows 8.1.

Categories