BLE communication between two Raspberry Pi 4 - python-3.x

I am collecting pressure sensor data from 4 Arduino Nano 33 ble to a raspberry pi 4. I am able to receive the data from all the sensors. Now, I want to send this received data to another Raspberry Pi 4 using BLE communication in real-time such that the first Raspberry Pi acts as a repeater. I searched but could not find a suitable approach or solution to implement this.
The first Raspberry Pi could act as a peripheral/client sending all the received sensor data and the second raspberry pi could act as a central/server to receive all the sensor data which can be further displayed on web interfaces or stored in a database.
I tried connecting initially with one Arduino and sending its data over raspberry Pi. I have written the code for Raspberry Pi Client and Server using Bluedot library in Python.
Raspberry Pi 4 Client code
import sys
import time
from bluepy import btle
from bluedot.btcomm import BluetoothClient
from signal import pause
def data_3():
mac_adrs3 = 'f3:9a:9a:e8:54:5c'
print("Connecting..")
tp3_sense = btle.Peripheral(mac_adrs3)
print("Discovering Services..")
_=tp3_sense.services
tire3_sensing_service = tp3_sense.getServiceByUUID("2b7537ab-8899-4359-a78a-096e076a4605")
print("Discovering characteristics..")
_= tire3_sensing_service.getCharacteristics()
return tire3_sensing_service
def byte_array_to_int(value):
value = bytearray(value)
value = int.from_bytes(value, byteorder='little')
return value
def byte_array_to_char(value):
value = value.decode("utf-8")
return value
def decimal_exponent_two(value):
return value/100
def decimal_exponent_one(value):
return value/10
def pascals_to_kilopascals(value):
return value / 1000
def read_pressure3(service3):
pres3_char = service3.getCharacteristics("9c30d6b2-e3d3-4eae-8641-425a36d550ec")[0]
pres3 = pres3_char.read()
pres3 = byte_array_to_int(pres3)
#pres3 = decimal_exponent_one(pres3)
#pres3 = pascals_to_kilopascals(pres3)
print(f"Barometric pressure 3 : {round(pres3,2)} kPa")
return pres3
def read_temperature3(service3):
temp3_char = service3.getCharacteristics("e986145c-ead6-41a7-9718-d2b0b4834a11")[0]
temp3 = temp3_char.read()
temp3 = byte_array_to_int(temp3)
#temp3 = decimal_exponent_two(temp3)
print(f"temperature 3 : {round(temp3,2)} C")
return temp3
def loop():
c = data_3()
while True:
time.sleep(1.0)
print("\n")
read_temperature3(c)
read_pressure3(c)
t3 = read_temperature3(c)
p3 = read_pressure3(c)
r = BluetoothClient("DC:A6:32:4C:9D:ED", data_received_callback=None, port=2)
r.send(f"temp 3 : {t3} ")
r.send("\n")
r.send(f"pressure 3 : {p3} ")
#pause()
#time.sleep(1.0)
def main():
loop()
if __name__ == "__main__":
main()
Raspberry Pi Server code
from bluedot.btcomm import BluetoothServer
from signal import pause
def data_received(data):
print(data)
s.send(data)
s = BluetoothServer(data_received)
pause()
I am able to receive two readings and after that the client disconnects with the below error.
pi#raspberrypi:~/Desktop/rpible $ python3 onearduino_senddata.py
Connecting..
Discovering Services..
Discovering characteristics..
temperature 3 : 0 C
Barometric pressure 3 : 100 kPa
temperature 3 : 0 C
Barometric pressure 3 : 100 kPa
Traceback (most recent call last):
File "onearduino_senddata.py", line 83, in <module>
main()
File "onearduino_senddata.py", line 80, in main
loop()
File "onearduino_senddata.py", line 70, in loop
r = BluetoothClient("DC:A6:32:4C:9D:ED", data_received_callback=None, port=2)
File "/usr/local/lib/python3.7/dist-packages/bluedot/btcomm.py", line 567, in __init__
self.connect()
File "/usr/local/lib/python3.7/dist-packages/bluedot/btcomm.py", line 660, in connect
self._client_sock.connect((server_mac, self._port))
OSError: [Errno 16] Device or resource busy
please help to solve this issue.

Found the solution.
Create the client once outside the while loop and then the data transfer happens.
updated loop function.
def loop():
c = data_3()
//create the client connection here
r = BluetoothClient("DC:A6:32:4C:9D:ED", data_received_callback=None)
while True:
time.sleep(1.0)
print("\n")
t3 = read_temperature3(c)
p3 = read_pressure3(c)
r.send(f"temp 3 : {t3} ")
r.send("\n")
r.send(f"pressure 3 : {p3} ")

Related

I want to merge two codes but keep giving me an error

Hi I am new to python and I am trying to record the sound when there is loudness is over a certain value (in the code 200).
Initially, I had two different pieces of code. one for recording and one for the detecting loudness. I want to merge together and record the sound when the loudness is over 200.
But This keeps giving me an error so I am wondering which part am I missing.
I would very appreciate if some one help me to figure this out.
import time
import grovepi
import os
import sys
sys.path.insert(0,'.')
from audio import soundrecord
loudness_sensor = 0
while True:
try:
# Read the sound level
sensor_value = grovepi.analogRead(loudness_sensor)
print("sensor_value = %d" %sensor_value)
time.sleep(.5)
if sensor_value> 200:
soundrecord()
time.sleep(10)
except IOError:
print ("Error")
I defined the below recording code as a soundrecord function and put it in the same directory
import pyaudio
import wave
def soundrecord():
form_1 = pyaudio.paInt16 # 16-bit resolution
chans = 1 # 1 channel
samp_rate = 44100 # 44.1kHz sampling rate
chunk = 4096 # 2^12 samples for buffer
record_secs = 3 # seconds to record
dev_index = 2 # device index found by p.get_device_info_by_index(ii)
wav_output_filename = 'test1.wav' # name of .wav file
audio = pyaudio.PyAudio() # create pyaudio instantiation
# create pyaudio stream
stream = audio.open(format = form_1,rate = samp_rate,channels = chans, \
input_device_index = dev_index,input = True, \
frames_per_buffer=chunk)
print("recording")
frames = []
# loop through stream and append audio chunks to frame array
for ii in range(0,int((samp_rate/chunk)*record_secs)):
data = stream.read(chunk)
frames.append(data)
print("finished recording")
# stop the stream, close it, and terminate the pyaudio instantiation
stream.stop_stream()
stream.close()
audio.terminate()
# save the audio frames as .wav file
wavefile = wave.open(wav_output_filename,'wb')
wavefile.setnchannels(chans)
wavefile.setsampwidth(audio.get_sample_size(form_1))
wavefile.setframerate(samp_rate)
wavefile.writeframes(b''.join(frames))
wavefile.close()
expecting: Record the sound when the loudness is over 200
actual :
sensor_value = 75
sensor_value = 268
Error
sensor_value = 360
Error
sensor_value = 48
sensor_value = 39
sensor_value = 79

Defining a file descriptor in python3 - to work with pyudev/evdev

I'm currently trying to detect the connexion of a bluetooth button on a raspberry pi 3 (that part works) and once connected, detect when the button is pressed (that part doesn't work).
I've started with the code provided by evdev and tried to tweak it for my use (see hereunder), but I cannot manage to create the correct file descriptor to use with select (if I correctly understood what's happening).
import functools
import pyudev
import evdev
from select import select
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='bluetooth')
monitor.start()
fds = {monitor.fileno(): monitor}
finalizers = []
while True:
r, w, x = select(fds, [], [])
if monitor.fileno() in r:
r.remove(monitor.fileno())
for udev in iter(functools.partial(monitor.poll, 0), None):
devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
for device in devices:
if device.name.strip() == 'AB Shutter3':
if udev.action == u'add':
print('Device added: %s' % udev)
fds[dev.fd] = device #This here breaks. dev.fd undefined.
break
if udev.action == u'remove':
print('Device removed: %s' % udev)
def helper():
global fds
fds = {monitor.fileno(): monitor}
finalizers.append(helper)
break
for fd in r:
dev = fds[fd]
for event in dev.read():
print(event)
for i in range(len(finalizers)):
finalizers.pop()()
The problem is that when I try to add the device, dev.fd is not defined. I've tried to define it, but I've got no idea how to define a file descriptor. What should I do ?
Device added: Device('/sys/devices/platform/soc/3f201000.serial/tty/ttyAMA0/hci0/hci0:64')
Traceback (most recent call last):
File "dev_status.py", line 27, in <module>
fds = {dev.fd:device} #This here breaks. dev.fd undefined.
NameError: name 'dev' is not defined
Other information : Raspberry Pi 3 running Raspbian Strech & Python 3.5.3
Also, this is my first question on Stack Overflow, so if anything's missing or could be more detailed, feel free to mention it.
Thanks,
Pôm'
OK, I've managed to find a solution. Here it is, if it can help anybody.
#!/usr/bin/env python3
import functools
import pyudev
import evdev
from select import select
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='bluetooth')
monitor.start()
fds = {monitor.fileno(): monitor}
time = 0.0
udevices = context.list_devices(subsystem='bluetooth')
link_up = False
for udevice in udevices :
if udevice.device_type == 'link' and udevice.is_initialized :
link_up = True
print('yiha')
evdevices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
if len(evdevices) > 0:
for evdevice in evdevices:
if evdevice.name.strip() == 'AB Shutter3' and link_up:
print('Device existing: %s' % udevice)
fds[evdevice.fileno()] = evdevice
while True:
r, w, x = select(fds, [], [])
if monitor.fileno() in r:
for udevice in iter(functools.partial(monitor.poll, 0), None):
evdevices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
for evdevice in evdevices:
if evdevice.name.strip() == 'AB Shutter3':
if udevice.action == u'add':
print('Device added: %s' % udevice)
fds[evdevice.fileno()] = evdevice
break
if udevice.action == u'remove':
print('Device removed: %s' % udevice)
fds.pop(evdevice.fileno(),None)
break
if evdevice.fileno() in r:
dev = fds[evdevice.fileno()]
for event in dev.read():
if event.type == evdev.ecodes.EV_KEY:
data = evdev.categorize(event)
if data.keystate == 1 and data.event.timestamp() - time > 0.05 :
if data.scancode == 115:
print("Big button")
elif data.scancode == 28:
print("Small button")
time = data.event.timestamp()
I'm pretty sure I will look at this in horror in a few months' time, but for the moment, it does the job.

Trying to convert telnetenable.py to Python 3.6 in Windows 10

I have a Costco R4500 router that I am trying to open up telnet on. The older telnetenable.py script is what is needed to send a TCP packet to open it up. Then the router can be upgraded/updated, as the only release of firmware available for it from Netgear is terrible.
The new telnetenable2 using UDP packets does work on Windows 10, but does not work on this older firmware. The older exe, telnetenable, using TCP, does not run on Windows 10.
I figured out I had to install Python. Then I have to use Cryptodome instead of Crypto. And apparently Visual Studio. I am not a programmer.
Installed Python, then got the crypto error, then realized the PyCrypto package is not longer maintained, then installed PyCryptoDome, and modified the telnetenable.py somewhat. Only I am not a programmer, so I have very basic knowledge. I have read a lot on the current error I am getting, but have no idea what to do. I have looked at the script, and was hoping someone could tell me what is wrong with it.
copy of code in pastebin
# Copyright (c) 2009 Paul Gebheim...
import sys
import socket
import array
from optparse import OptionParser
from Cryptodome.Cipher import Blowfish
from Cryptodome.Hash import MD5
TELNET_PORT = 23
# The version of Blowfish supplied for the telenetenable.c implementation
# assumes Big-Endian data, but the code does nothing to convert the
# little-endian stuff it's getting on intel to Big-Endian
#
# So, since Crypto.Cipher.Blowfish seems to assume native endianness, we need
# to byteswap our buffer before and after encrypting it
#
# This helper does the byteswapping on the string buffer
def ByteSwap(data):
a = array.array('i')
if(a.itemsize < 4):
a = array.array('L')
if(a.itemsize != 4):
print("Need a type that is 4 bytes on your platform so we can fix the data!")
exit(1)
a.fromstring(data)
a.byteswap()
return a.tostring()
def GeneratePayload(mac, username, password=""):
# Pad the input correctly
assert(len(mac) < 0x10)
just_mac = mac.ljust(0x10, "\x00")
assert(len(username) <= 0x10)
just_username = username.ljust(0x10, "\x00")
assert(len(password) <= 0x10)
just_password = password.ljust(0x10, "\x00")
cleartext = (just_mac + just_username + just_password).ljust(0x70, '\x00')
md5_key = MD5.new(cleartext).digest()
payload = ByteSwap((md5_key + cleartext).ljust(0x80, "\x00"))
secret_key = "AMBIT_TELNET_ENABLE+" + password
return ByteSwap(Blowfish.new(secret_key, 1).encrypt(payload))
def SendPayload(ip, payload):
for res in socket.getaddrinfo(ip, TELNET_PORT, socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_IP):
af, socktype, proto, canonname, sa = res
try:
s = socket.socket(af, socktype, proto)
except socket.error as msg:
s = None
continue
try:
s.connect(sa)
except socket.error as msg:
s.close()
s= None
continue
break
if s is None:
print ("Could not connect to '%s:%d'") % (ip, TELNET_PORT)
else:
s.send(payload)
s.close()
print ("Sent telnet enable payload to '%s:%d'") % (ip, TELNET_PORT)
def main():
args = sys.argv[1:]
if len(args) < 3 or len(args) > 4:
print ("usage: python telnetenable.py <ip> <mac> <username> [<password>]")
ip = args[0]
mac = args[1]
username = args[2]
password = ""
if len(args) == 4:
password = args[3]
payload = GeneratePayload(mac, username, password)
SendPayload(ip, payload)
main()
md5_key = MD5.new(cleartext).digest()
This is where I get the error:
Traceback (most recent call last):
File "telnetenable.py", line 113, in <module>
main()
File "telnetenable.py", line 110, in main
payload = GeneratePayload(mac, username, password)
File "telnetenable.py", line 64, in GeneratePayload
md5_key = MD5.new(cleartext).digest()
File "C:\Users\farme\AppData\Local\Programs\Python\Python36\lib\site-packages\Cryptodome\Hash\MD5.py", line 47, in __init__
self._h = _hash_new(*args)
TypeError: Unicode-objects must be encoded before hashing
It looks to me that the arguments you are passing to the script are in unicode and the MD5 object wants it encoded prior to processing it. I think the encoding will put one symbol per byte rather than allowing any confusion that any multi-byte characters might create if there is also a single byte option for that character.
Try something this:
md5_key = MD5.new(cleartext.encode('utf-8)).digest()

How to implement High pass audio filter for a wav file in python

I am working on a project related to audio processing and I want to implement a high pass audio filter for some wave files stored in memory and on live speech also. I found some previously asked question here related to my problem but not exactly like
1-> Python scipy.signal.remez high pass filter design yields strange transfer function
2-> Python: High Pass FIR Filter by Windowing
but I am not getting how can I modify the available code for saved audio files and for live speech also .
i have found a piece of code for low pass filter for saved audio file which is working fine but I am unable to find one for high pass filter.
file_input = '3.wav'
file_output = 'filter.wav'
cutOffFrequency = 400.0
def running_mean(x, windowSize):
cumsum = np.cumsum(np.insert(x, 0, 0))
return (cumsum[windowSize:] - cumsum[:-windowSize]) / windowSize
def interpret_wav(raw_bytes, n_frames, n_channels, sample_width, interleaved = True):
if sample_width == 1:
dtype = np.uint8
elif sample_width == 2:
dtype = np.int16
else:
raise ValueError("Only supports 8 and 16 bit audio formats.")
channels = np.fromstring(raw_bytes, dtype=dtype)
if interleaved:
channels.shape = (n_frames, n_channels)
channels = channels.T
else:
channels.shape = (n_channels, n_frames)
return channels
with contextlib.closing(wave.open(file_input,'rb')) as spf:
sampleRate = spf.getframerate()
ampWidth = spf.getsampwidth()
nChannels = spf.getnchannels()
nFrames = spf.getnframes()
signal = spf.readframes(nFrames*nChannels)
spf.close()
channels = interpret_wav(signal, nFrames, nChannels, ampWidth, True)
freqRatio = (cutOffFrequency/sampleRate)
N = int(math.sqrt(0.196196 + freqRatio**2)/freqRatio)
filtered = running_mean(channels[0], N).astype(channels.dtype)
wav_file = wave.open(file_output, "w")
wav_file.setparams((1, ampWidth, sampleRate, nFrames, spf.getcomptype(), spf.getcompname()))
wav_file.writeframes(filtered.tobytes('C'))
wav_file.close()
This is the code I am using for low pass filter .

python, removing parts of a list (and a bit more)

I'm making a music player for my raspberry pi.
It is shoud remove '/home/pi/Desktop/Muziek/'from the strings in my list.But i keep getting this error:
Traceback (most recent call last):
File "/home/pi/Desktop/Music Player(Alpha2.2).py", line 19, in <module>
pygame.mixer.music.load(SongPath + Song[0])
error: Couldn't open ' Toto - Africa.mp3'
>>>
I think it is because of the space between ' and Toto but I don't know how to fix it. BTW here is the code:
import glob
Song1 = glob.glob('/home/pi/Desktop/Muziek/*.mp3')
Song2 = glob.glob('/home/pi/Desktop/Muziek/*.ogg')
Song = Song1 + Song2
Song = [s.strip('/home/pi/Desktop/Muziek/') for s in Song]
Song = [s.replace('/home/pi/Desktop/Muziek/','') for s in Song]
SongPath = '/home/pi/Desktop/Muziek/
print('Music Player(Alpha2.2)')
import pygame
from time import sleep
Song = sorted(Song)
CurrentSong = 0
State = 'Playing'
pygame.mixer.init()
pygame.mixer.music.load(SongPath + Song[0])
pygame.mixer.music.play()
print("Songs:")
for i in range(0, len(Song)):
print(i+1, Song[i])
print('\nStarted auto play on:\n' + Song[CurrentSong])
I used os.listdir('') instead of glob.

Resources