2

I put together a Kivy App that gets the coordinates from a user touch and sends them over bluetooth to an arduino

I am following the steps on how to handle bluetooth on android listed in the link below: https://developer.android.com/guide/topics/connectivity/bluetooth#ManageAConnection

Fct ConnectBluetooth() is called when pressing a "connect to bluetooth" button. This is where I look for the arduino HC-05 bluetooth receiver and setup a socket as well as the input and output streams.

I then use the fct SendCoordinates() to use the output stream and send data over bluetooth. However, when this function is called, I get the following error: error while sending bluetooth data on Android

I thought the argument you pass over to the write() function of the outputstream has to be a byte array. I guess its not. Does anyone know what I have to pass instead? I am doing something wrong while converting the string to byte array?( "ByteString = bytes(StrPositionData,'utf-8')")

While I'm on the subject, how does one use the inPutStream to read bluetooth data from my Kivy on android? The guide states read(byte[]) "should be called in a separate thread" because it blocks until it receives data. How does one add this separate thread in python?

Code is listed below:

main.py:

import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.anchorlayout import AnchorLayout
#from subprocess import Popen,PIPE
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.image import Image
from kivy.utils import get_color_from_hex
from kivy.graphics import Color, Rectangle
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.core.text import LabelBase
from jnius import autoclass
UUID = autoclass('java.util.UUID')


LabelBase.register(name="Nobile",
                   fn_bolditalic="fonts/Nobile/Nobile-BoldItalic.ttf",
                   fn_regular="fonts/Nobile/Nobile-Regular.ttf")

class HomeScreen(Screen):

    mvoltage = ObjectProperty(None)
    print('Start')
    port = "COM4"
    BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter')
   
    #init input & output streams            
    SendSerialData = None
    ReceiveSerialData = None

    #flag to signal initialized bluetooth    
    BluetoothInit = 0

    def __init__(self, **kwargs):
        super(HomeScreen, self).__init__(**kwargs)
        #Clock.schedule_interval(self.ReceiveSerialData, 2)
        try:
            print("Looking for Bluetooth On Windows")
            #bluetooth_device = serial.Serial(self.port, 9600, timeout=1)
            print("Connected to HC-05")
        except Exception as e:
            print("Looking for Bluetooth On Android")


    def SendCoordinates(self, XCoordinate, YCoordinate):
       
        #conver positionData to string
        StrPositionData = str(XCoordinate)+','+' '+str(YCoordinate)
        ByteString = bytes(StrPositionData,'utf-8')
        self.SendSerialData.write('{}\n'.format(ByteString))
        self.SendSerialData.flush()


    def on_touch_down(self, touch):

        if self.BluetoothInit == 1:
            self.SendCoordinates(touch.sx, touch.sy)

        return super(HomeScreen,self).on_touch_down(touch)

    def on_touch_up(self,touch):
        try:
            self.bluetooth_device.write(b"STOP")
            print('STOP'.encode())
        except:
            pass

    def on_touch_move(self, touch):
        pass



    def ReceiveSerialData(self,dt):
        Serial_Data=[124]
        ReceivedBytes = 0

        try:
            Serial_Data = self.bluetooth_device.readline().decode()
        except:
            if self.BluetoothInit == 1:
            ReceivedBytes = self.ReceiveSerialData.read(Serial_Data)
            print(Serial_Data)            

        #Number = int(Serial_Data)
        #if Number >= 10000:
            #NR = Serial_Data[0:2]
            #Decimals = Serial_Data[2:4]
        #else:
            #NR = Serial_Data[0]
            #Decimals = Serial_Data[1:3]

        #self.mvoltage.text = NR + '.' + Decimals + '  ' + 'Volts'


    def ConnectBluetooth(self):
        #try to connect on windows
        try:
            print("Connecting to Bluetooth" )
            self.port = "COM4"
            self.bluetooth_device = serial.Serial(self.port, 9600, timeout=1)
            print("Connected to HC-05")
        #windows failed, try connecting on Android
        except Exception as e1:
            paired_devices = self.BluetoothAdapter.getDefaultAdapter().getBondedDevices().toArray()
            socket = None
            for device in paired_devices:
                if device.getName() == 'HC-05':
                    socket = device.createRfcommSocketToServiceRecord(
                        UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"))
                    self.ReceiveSerialData = socket.getInputStream()
                    self.SendSerialData = socket.getOutputStream()
                    break
            socket.connect()

            #signal that bluetooth connection established
            self.BluetoothInit = 1
        except Exception as e2:
            raise Exception('Cant Connect Bluetooth on Windows or Android')




class SecondScreen(Screen):
    pass

class WindowManager(ScreenManager):
    pass


kv=Builder.load_file('Crane.kv')

class MainApp(App):
    def build(self):
        return kv

if __name__ == "__main__":
    TestApp = MainApp()
    TestApp.run()

.kv file:

#:import utils kivy.utils
WindowManager:
    HomeScreen:
    SecondScreen:

<HomeScreen>:
    name: "Crane App"
    mvoltage:MotorVoltage
    FloatLayout:
        canvas.before:
            Color:
                rgb: utils.get_color_from_hex("#ffffff")
            Rectangle:
                size: self.size
                pos: self.pos
        GridLayout:
            canvas.before:
                Color:
                    rgb: utils.get_color_from_hex("#ffffff")
                Rectangle:
                    size: self.size
                    pos: self.pos
            rows: 1
            cols: 3
            padding:10
            FloatLayout:
                GridLayout:
                    canvas.before:
                        Color:
                            rgb: utils.get_color_from_hex("#ffffff")
                        Rectangle:
                            size: self.size
                            pos: self.pos
                    rows: 2
                    cols: 1
                    spacing:5
                    padding:5
                    pos_hint:{"top": 1, "left": 1}
                    Image:
                        source: "icons/extend_boom.PNG"
                        allow_stretch: True
                        keep_ratio: False
                    Image:
                        source: "icons/lift_boom.PNG"
                        allow_stretch: True
                        keep_ratio: False

                AnchorLayout:
                    id:Anchor_Left
                    pos_hint:{"left": 0.60, "top": 1}
                    size_hint: 1, 1
                    GridLayout:
                        id:LeftButtons
                        rows:2
                        Button:
                            id:extend_boom
                            background_color:(255,255,255,0)

                        Button:
                            id:lift_boom
                            background_color:(255,255,255,0)

            GridLayout:
                canvas.before:
                    Color:
                        rgb: utils.get_color_from_hex("#ffff00")
                    Rectangle:
                        size: self.size
                        pos: self.pos
                rows: 5
                cols: 1
                padding:5
                spacing:5
                size_hint: .54, 1

                Label:
                    text:"Motor Voltage"
                    color: 0,0,0,1
                    font_name:"Nobile"
                    bold:True

                TextInput:
                    id:MotorVoltage

                Label:
                    text:"Controller Voltage"
                    color: 0,0,0,1
                    font_name:"Nobile"
                TextInput:
                    id: ControllerVoltage
                Button:
                    id:connect_bluetooth
                    text:"Connect to Bluetooth"
                    background_color:(0,0,0,0.9)
                    on_press:
                        root.ConnectBluetooth()
            FloatLayout:
                GridLayout:
                    canvas.before:
                        Color:
                            rgb: utils.get_color_from_hex("#ffffff")
                        Rectangle:
                            size: self.size
                            pos: self.pos
                    rows: 2
                    cols: 1
                    spacing:5
                    padding:5
                    pos_hint:{"top": 1, "right": 1}
                    Image:
                        source: "icons/lift_hook.PNG"
                        allow_stretch: True
                        keep_ratio: False
                    Image:
                        source: "icons/rotate.PNG"
                        allow_stretch: True
                        keep_ratio: False

                AnchorLayout:
                    id:Anchor_Right
                    pos_hint:{"right": 1, "top": 1}
                    size_hint: 1, 1
                    GridLayout:
                        id:LeftButtons
                        rows:2
                        Button:
                            id:lift_hook
                            background_color:(255,255,255,0)

                        Button:
                            id:rotate
                            background_color:(255,255,255,0)


<SecondScreen>:
    name: "Passenger Contact Info"
    Button:
        text: "Go Back"
        on_press:
            app.root.current="Bus Map"
            root.manager.transition.direction="left"

Thanks in advance for your help.

Alex

Alex
  • 57
  • 2
  • 8

1 Answers1

3

Figuered out how to use the Android APIs to send & receive bluetooth data. I am posting the Code for any other Kivy beginners :)

from jnius import autoclass

class AndroidBluetoothClass:

    def getAndroidBluetoothSocket(self,DeviceName):
        paired_devices = self.BluetoothAdapter.getDefaultAdapter().getBondedDevices().toArray()
        socket = None
        for device in paired_devices:
            if device.getName() == DeviceName:
                socket = device.createRfcommSocketToServiceRecord(
                    self.UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"))
                self.ReceiveData = self.BufferReader(self.InputStream(socket.getInputStream()))
                self.SendData = socket.getOutputStream()
                socket.connect()
                self.ConnectionEstablished = True
                print('Bluetooth Connection successful')
        return self.ConnectionEstablished


    def BluetoothSend(self, Message, *args):
        if self.ConnectionEstablished == True:
            self.SendData.write(Message)
        else:
            print('Bluetooth device not connected')


    def BluetoothReceive(self,*args):
        DataStream = ''
        if self.ConnectionEstablished == True:
            DataStream = str(self.ReceiveData.readline())
        return DataStream


    def __init__(self):
        self.BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter')
        self.BluetoothDevice = autoclass('android.bluetooth.BluetoothDevice')
        self.BluetoothSocket = autoclass('android.bluetooth.BluetoothSocket')
        self.UUID = autoclass('java.util.UUID')
        self.BufferReader = autoclass('java.io.BufferedReader')
        self.InputStream = autoclass('java.io.InputStreamReader')
        self.ConnectionEstablished = False


    def __del__(self):
        print('class AndroidBluetooth destroyer')

Import the "AndroidBluetoothClass" in your project, create an AndroidBluetooth = AndroidBluetoothClass() object and use the methods in the class as follows:

  • AndroidBluetooth.getAndroidBluetoothSocket('HC-05') to connect to the arduino HC-05 bluetooth
  • AndroidBluetooth.BluetoothSend(b'1'): parameter has to be a byte array
  • SerialData=''/ SerialData = AndroidBluetooth.BluetoothReceive()

Hope this helps any Kivy beginners out there

Alex
  • 57
  • 2
  • 8