I want to convert a python code used to connect bluetooth device to Raspberry pi to C code. Is it possible?? Is there a way to connect a bluetooth device to raspberry pi using c programming.
The code is given below:
import pygatt
from binascii import hexlify
import time
adapter = pygatt.GATTToolBackend()
def handle_data(handle, value):
"""
handle -- integer, characteristic read handle the data was received on
value -- bytearray, the data returned in the notification
"""
print("Received data: %s" % hexlify(value))
try:
adapter.start()
device = adapter.connect('AC:23:3F:AA:36:7C')
device.subscribe("7f280002-8204-f393-e0a9-e50e24dcca9e",
callback=handle_data)
# The subscription runs on a background thread. You must stop this main
# thread from exiting, otherwise you will not receive any messages, and
# the program will exit. Sleeping in a while loop like this is a simple
# solution that won't eat up unnecessary CPU, but there are many other
# ways to handle this in more complicated program. Multi-threaded
# programming is outside the scope of this README.
while True:
time.sleep(10)
finally:
adapter.stop()
Two choices that I know of: https://github.com/petzval/btferret and
https://github.com/weliem/bluez_inc. This is equivalent btferret code.
/********* DEVICES.TXT file ************
DEVICE = My Pi TYPE=mesh node=1 ADDRESS = B8:27:EB:F1:50:C3
DEVICE = LE device TYPE=LE NODE=7 ADDRESS = AC:23:3F:AA:36:7C
*******************************************/
/******** C file *****************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "btlib.h"
int callback(int clientnode,int cticn,unsigned char *dat,int len);
int main()
{
int cticn;
if(init_blue("devices.txt") == 0)
return(0);
// connect to LE device, node 7
connect_node(7,CHANNEL_LE,0);
find_ctics(7);
cticn = find_ctic_index(7,UUID_16,strtohex("7f280002-8204-f393-e0a9-e50e24dcca9e",NULL));
notify_ctic(7,cticn,NOTIFY_ENABLE,callback);
read_notify(10000); // read for 10s
close_all();
return(0);
}
int callback(int clientnode,int cticn,unsigned char *dat,int len)
{
int n;
printf("Notify =");
for(n = 0 ; n < len ; ++n)
printf(" %02X",dat[n]);
printf("\n");
return(SERVER_CONTINUE);
}
Related
I Used Rpi 3B+ to read sensor data from Arduino Uno with JDY-18 bluetooth module. JDY-18 can connect to Rpi, but can't receive sensor data.
My Arduino code like this :
#include <SoftwareSerial.h>
#include "LowPower.h" // For Arduino Sleep Mode
SoftwareSerial BTSerial(2, 3); // RX | TX
int soilMoisureInt;
void setup()
{
pinMode(A0, INPUT);
BTSerial.begin(9600);
Serial.begin(9600);
}
void loop()
{
// Make initial soilMoisureInt equal zero
soilMoisureInt = analogRead(A0);
// Send data through bluetooth
BTSerial.write(soilMoisureInt);
// Get Arduino into sleep mode
for (int i = 0 ; i < 2 ; i++)
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
}
And my Rpi code like this (use bluepy Python3 package):
import bluepy.btle as btle
# Set up variables
dataInt = None
blue_address = "XX:XX:XX:XX:XX:XX"
# For bluepy Peripheral class
class ReadDelegate(btle.DefaultDelegate):
def handleNotification(self, cHandle, data):
# Access global variables insid class
global dataInt
# Change ascii char to int
dataInt = ord(data)
# Connect to bluetooth module
p = btle.Peripheral(blue_address)
# Use ReadDelegate
p.withDelegate(ReadDelegate())
# Read date
while True:
p.waitForNotifications(0)
print("Soil Moisure : " + str(dataInt))
Could anyone have the experience of connection between JDY-18 and Rpi?
I have 3 arduino's that have RC522 rfid readers attached to them. They each have their own power supplies and they are connected to a raspberry pi 3 via the usb ports. I am getting really inconsistent results when running the reader in python. It does appear all 3 are reading but the loop does some weird things. Sometimes the chip code keeps repeating after the chip is removed and other times it works properly. There does not appear to be any consistency with which arduino is behaving oddly either.
Any help would be greatly appreciated!!!
Here is the arduino code (The same code was copied to each arduino with the exception of the initial println that indicates which arduino is connected).
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 5 // Configurable, see typical pin layout above
#define SS_PIN 53 // Configurable, see typical pin layout above
#define MOSI_PIN 51
#define MISO_PIN 50
#define SCK_PIN 52
MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
MFRC522::MIFARE_Key key;
String read_rfid;
void setup() {
Serial.begin(9600);
SPI.begin(); // Init SPI bus
rfid.PCD_Init(); // Init MFRC522
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println(F("The Toy Maker's Sanctuary RDIF Reader 1 Online."));
//Serial.println(F("Using the following key:"));
//printHex(key.keyByte, MFRC522::MF_KEY_SIZE);
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( ! rfid.PICC_IsNewCardPresent())
return;
// Select one of the cards
if ( ! rfid.PICC_ReadCardSerial())
return;
dump_byte_array(rfid.uid.uidByte, rfid.uid.size);
Serial.println(read_rfid);
}
/*
Helper routine to dump a byte array as hex values to Serial.
*/
void dump_byte_array(byte *buffer, byte bufferSize) {
read_rfid = "";
for (byte i = 0; i < bufferSize; i++) {
read_rfid = read_rfid + String(buffer[i], HEX);
}
}
Here is the python code
import serial
ser0=serial.Serial("/dev/ttyACM0", 9600, timeout=1)
ser1=serial.Serial("/dev/ttyACM1", 9600, timeout=1)
ser2=serial.Serial("/dev/ttyACM2", 9600, timeout=1)
ser0.baudrate=9600
ser1.baudrate=9600
ser2.baudrate=9600
read_ser0=""
read_ser1=""
read_ser2=""
while True:
read_ser0=ser0.readline()
print("0: ",read_ser0)
read_ser1=ser1.readline()
print("1: ",read_ser1)
read_ser2=ser2.readline()
print("2: ",read_ser2)
read_ser0=""
read_ser1=""
read_ser2=""
I am trying to send an int number from Python to an Arduino using PySerial, using .write([data]) to send with Python and Serial.read() or Serial.readString() to recieve on the Arduino, then .setPixelColor() and .show() to light a LED on a matrix which position corresponds to the int sent by the arduino (I am using the Duinofun Neopixel Shield).
But It does not seem to work properly, and I can't use the Serial Monitor as I am sending my data as the port would be busy.
I have tried to input a number myself using Serial.readString() then converting the string to an int and finally putting in into my function that displays the LED.
It does work properly when I do this, but when I send some data over, all the previously lit LEDs suddenly switch off which can only be caused by a reset of the Arduino board as far as I know.
This is the python code, it simply sends an int chosen by the user
import serial
a = int(input('Enter pixel position : '))
ser = serial.Serial("COM16", 9600)
ser.write([a])
And this is the part of the Arduino program that reads the incoming data.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(40, 6, NEO_GRB + NEO_KHZ800);
void setup() {
// put your setup code here, to run once:
pixels.begin();
Serial.begin(9600);
}
void loop() {
String a = Serial.readString();
int b = a.toInt();
pixels.setPixelColor(b, 30,30,30);
pixels.show();
Serial.println(a);
delay(1000);
}
All the LED switch off when I send some data, except the first LED which position corresponds to a 0 used in the .setPixelColor() function.
Problem is, the LED should light to the corresponding int sent by Python (e.g light the fifth LED for an int of 4).
You don't need to send an int from your Python script. Just send a string and then convert it back to int on your Arduino. Also, you can verify the number simply on your Arduino code if the received value is valid.
Another problem with your Arduino code is you are not checking the Serial port availability which would return an empty string by Serial.readString().
A simple approach is shown below but you can extend it for other pixels.
Python script:
import serial
ser = serial.Serial("COM16", 9600)
while True:
input_value = input('Enter pixel position: ')
ser.write(input_value.encode())
Arduino code:
#define MIN_PIXEL_RANGE 0
#define MAX_PIXEL_RANGE 100
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(40, 6, NEO_GRB + NEO_KHZ800);
void setup()
{
// put your setup code here, to run once:
pixels.begin();
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{
String a = Serial.readString();
Serial.print("Received Value: ");
Serial.println(a);
int b = a.toInt();
if ((b >= MIN_PIXEL_RANGE) && (b <= MAX_PIXEL_RANGE))
{
pixels.setPixelColor(b, 30, 30, 30);
pixels.show();
delay(1000);
}
}
}
You can communicate between Ardinos and Python really easily and reliably if you use the pip-installable package pySerialTransfer. The package is non-blocking, easy to use, supports variable length packets, automatically parses packets, and uses CRC-8 for packet corruption detection.
Here's an example Python script:
from pySerialTransfer import pySerialTransfer as txfer
if __name__ == '__main__':
try:
link = txfer.SerialTransfer('COM13')
link.txBuff[0] = 'h'
link.txBuff[1] = 'i'
link.txBuff[2] = '\n'
link.send(3)
while not link.available():
if link.status < 0:
print('ERROR: {}'.format(link.status))
print('Response received:')
response = ''
for index in range(link.bytesRead):
response += chr(link.rxBuff[index])
print(response)
link.close()
except KeyboardInterrupt:
link.close()
Note that the Arduino will need to use the library SerialTransfer.h. You can install SerialTransfer.h using the Arduino IDE's Libraries Manager.
Here's an example Arduino sketch:
#include "SerialTransfer.h"
SerialTransfer myTransfer;
void setup()
{
Serial.begin(115200);
Serial1.begin(115200);
myTransfer.begin(Serial1);
}
void loop()
{
myTransfer.txBuff[0] = 'h';
myTransfer.txBuff[1] = 'i';
myTransfer.txBuff[2] = '\n';
myTransfer.sendData(3);
delay(100);
if(myTransfer.available())
{
Serial.println("New Data");
for(byte i = 0; i < myTransfer.bytesRead; i++)
Serial.write(myTransfer.rxBuff[i]);
Serial.println();
}
else if(myTransfer.status < 0)
{
Serial.print("ERROR: ");
Serial.println(myTransfer.status);
}
}
Lastly, note that you can transmit ints, floats, chars, etc. using the combination of these libraries!
I have connected my raspi (Master) with Arduino Mega (Slave) and want to continuously transfer the analog readings from analog pins A0-A3 to the raspi. Program runs for some time and the crashes giving me:
[Errno 121] Remote I/O Error
I am suspecting 2 things could be the problem: 1) The while loop => longer sleep times result in a longer running time until the program crashes 2) I read somewhere that the wire library does an onReceive command before it does an onRequest?
Here is my Arduino and raspi code:
Arduino Mega Code
#include
int SLAVE_ADDRESS = 0x08;
int analogPin1 = A0;
int analogPin2 = A1;
int analogPin3 = A2;
int analogPin4 = A3;
void setup(){
Wire.begin(SLAVE_ADDRESS);
Wire.onRequest(sendAnalogReading);
}
void loop(){
}
void sendAnalogReading(){
uint16_t reading1 = analogRead(analogPin1);
uint16_t reading2 = analogRead(analogPin2);
uint16_t reading3 = analogRead(analogPin3);
uint16_t reading4 = analogRead(analogPin4);
Wire.write((char *) &reading1, 2);
Wire.write((char *) &reading2, 2);
Wire.write((char *) &reading3, 2);
Wire.write((char *) &reading4, 2);
}
This is the script on my Raspi:
import smbus
import time
bus = smbus.SMBus(1)
SLAVE_ADDRESS = 0x08
def requestreading():
block = bus.read_i2c_block_data((SLAVE_ADDRESS), 0, 8)
print(block)
while True:
#var = input("Press any key for reading: ")
requestreading()
time.sleep(0.1)
The could should run continuously however i feel the actual runtime until it crashes depends on 2 factors. Length of time.sleep() in my while loop and if the measured values change much.
I'm trying to write analog readings from a potentiometer connected to an Arduino and read those values using I2C from python on an RPi. I have gotten Arduino to Arduino to work using the code below. What I cannot seem to do correctly is write two bytes from the Arduino and read two bytes from the RPi.
Arduino Master code:
#include <Wire.h>
#define SLAVE_ADDRESS 0x2a
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop()
{
Wire.requestFrom(SLAVE_ADDRESS, 2); // request 2 bytes from slave
byte loByte;
byte hiByte;
if(Wire.available() >= 2) // slave may send less than requested
{
hiByte = Wire.read();
loByte = Wire.read();
}
int val = (hiByte << 8) + loByte;
Serial.print("read value:");
Serial.println(val);
delay(500);
}
Arduino Slave code:
#include <Wire.h>
#include <stdlib.h>
#define SLAVE_ADDRESS 0x2a
//#define potPin 0
int readVal;
byte hi;
byte lo;
void setup()
{
// Communication I2C
Wire.begin(SLAVE_ADDRESS);
Wire.onRequest(requestEvent); // register event
Serial.begin(9600);
}
void loop()
{
readVal = analogRead(A2);
Serial.println(readVal);
hi = highByte(readVal);
lo = lowByte(readVal);
}
void requestEvent()
{
byte buf [2];
buf [0] = hi;
buf [1] = lo;
Wire.write(buf, sizeof buf); // send 2-byte response
}
The closest I have gotten reading from an RPi is:
RPi Master code:
import smbus
import time
bus = smbus.SMBus(1)
address = 0x2a
while True:
bus.write_byte(address, 1)
number = bus.read_byte(address)
print(number)
time.sleep(1)
Arduino slave code:
#include <Wire.h>
#define SLAVE_ADDRESS 0x2a
int number = 0;
void setup() {
Wire.begin(SLAVE_ADDRESS);
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
}
void loop() {
}
void receiveData(int byteCount){
while(Wire.available()) {
number = Wire.read();
number = analogRead(A2);
}
}
void sendData(){
Wire.write(number);
}
I seem to be able to get 0-255, but after 255 the value starts again. No doubt there is a more precise way to say I am only getting one byte of data or something along those lines. Ultimately I want to have 2 pots connected to the Arduino feeding readings into the RPi.
On Arduino, analogRead returns an int value in the range 0-1023. On this hardware, an int is two bytes.
However, the form of Wire.write that you use in the sendData function only writes a single byte, discarding part of the integer.
There are basically two solutions.
The simplest would be to take the return value of analogRead, divide it by 4 and cast it into a byte. Send that out with Wire.write. This does reduce the resolution of the value of the pot-meter, but is it a very simple solution.
The other was is to send an integer value over the wire. Since you're reading bytes on the RPi, you cannot know if you are reading the first or second byte of an integer. So you would probably have to use a signal to indicate the start of a two-byte sequence. You would also have to take the endian-ness of both platform into account. All in all, this is much more complicated.
Thanks for the feedback. It helped me think through this a bit more and do more digging. This is what I have working.
Arduino side for writing:
#include <Wire.h>
#define SLAVE_ADDRESS 0x2a
#define pot1pin A2
#define pot2pin A3
byte pot1byte;
byte pot2byte;
void setup()
{
Wire.begin(SLAVE_ADDRESS);
Wire.onRequest(requestEvent);
}
void loop() {
int pot1int = analogRead(pot1pin);
int pot2int = analogRead(pot2pin);
pot1byte = map(pot1int, 0, 1024, 0, 255);
pot2byte = map(pot2int, 0, 1024, 0, 255);
}
void requestEvent()
{
Wire.write(pot1byte);
delay(30);
Wire.write(pot2byte);
}
RPi side for reading:
import smbus
bus = smbus.SMBus(1)
address = 0x2a
while (1):
block = bus.read_i2c_block_data(address, 0, 2) # Returned value is a list of 2 bytes
print(block)
As you can see I am reading 2 pots, converting the output to 0-255, writing to the I2C bus and then reading the 2 bytes on the RPi side. I did have to change the Arduino delay value during testing because I was getting the error "IOError: [Errno 5] Input/output error" after a few minutes. Now maybe I will go back and write 2 bytes per pot and read 4 bytes so I don't lose and resolution.