Enabling Python Autocomplete in VIM on Raspberry Pi


This post shows steps to enable Python autocomplete in vim editor [1] on Raspberry Pi.

In this post, jedi-vim [2] and Vundle.vim [3] will be used for autocomplete plugin and plugin manager respectively. Also, even Raspbian Stretch has vim preinstalled, it’s a minimal version which is called “vim.tiny” and to use the plugin, we need to install another version of vim.

 

Prerequisites (parentheses indicate tested setup)

 

Steps
1. Install VIM
As mentioned above, another version of vim than the preinstalled one needs to be installed.

1-1. Update the package list.

sudo apt-get update

1-2. Install vim-nox.

sudo apt-get install vim-nox -y

 

2. Setup VIM
2-1. Clone VundleVim plugin.

git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim

2-2. Create a vim configuration file with vim.

vim ~/.vimrc

2-3. Activate the paste mode by the command below.

:set paste

2-4. Type “i” to go insert mode. Make sure that the paste mode is on as below.

-- INSERT (paste) --

2-5. Copy and paste the lines from line 1 to line 10 below.
Note: The lines after line 13 are my preferred settings and just for my reference. 

set nocompatible                  " be iMproved, required
filetype off                      " required
set rtp+=~/.vim/bundle/Vundle.vim " set the runtime path to include Vundle and initialize 
call vundle#begin()
Plugin 'VundleVim/Vundle.vim'     " let Vundle manage Vundle, required
Plugin 'davidhalter/jedi-vim'     " jedi-vim

" All of your Plugins must be added before the following line
call vundle#end()                 " required
filetype plugin indent on         " required

" Put your non-Plugin stuff after this line
colo murphy      " set colorscheme 
syntax enable    " enable syntax highlighting 
set number       " show line numbers 
set mouse=a      " turn on xterm style mousing which allows to select text w/o line numbers 
set clipboard=unnamedplus " copy yanked text to system clipboard 
set ts=4         " set tabs to have 4 spaces
set autoindent   " indent when moving to the next line while writing code 
set expandtab    " expand tabs into spaces 
set shiftwidth=4 " when using the >> or << commands, shift lines by 4 spaces 
set cursorline   " show a visual line under the cursor's current line 
set showmatch    " show the matching part of the pair for [] {} and () 
set laststatus=2 " display file name on the bottom bar
set pastetoggle=<F3> "paste mode toggling
let python_highlight_all = 1 " enable all Python syntax highlighting features
highlight OverLength ctermbg=red ctermfg=white guibg=#592929
match OverLength /\%81v.\+/

2-6. Exit the insert mode by pressing “Ctrl” + “[“.

2-7. Save the file by typing “:w” and enter.

:w

2-8. Execute the file by the command below.

:source %

2-9. Install the plugins by entering the command below.

:PluginInstall

It will show “Processing” in the status bar. It takes a while.

2-10. When the status bar shows “Done!”, close the file by entering “:q”.

 

3. Verify Autocomplete

 

References
[1] Vim – the ubiquitous text editor
[2] jedi-vim – awesome Python autocompletion with VIM – GitHub
[3] Vundle.vim – GitHub
[4] jedi-vim – Vim Awesome
[5] VIM and Python – A Match Made in Heaven

 

 

Setting Up Bluetooth Serial Port Profile on Raspberry Pi using D-Bus API

This post shows steps to set up Bluetooth Serial Port Profile[1] (or SPP) on Raspberry Pi.

The goal is to establish an SPP connection between Raspberry Pi 3 and Android phone, then send and receive texts using serial terminal applications on both ends.

SPP is not available by default. There are two options to enable it in BlueZ (which is the default Bluetooth stack in Linux). This post shows steps for the 2nd option (D-Bus API).

  1. sdptool (please see this post for this option)
  2. D-bus API

 

Prerequisites (parentheses indicate my environment)

 

Steps
1. Installation
1-1. Install a serial terminal application on Raspberry Pi. In this post, I’ll use minicom[2].

sudo apt-get install minicom -y

 

2. Enable SPP on Raspberry Pi
2-1. Create a python script (e.g. “spp.py”)[3][4].

import dbus, time

service_record = """
<?xml version="1.0" encoding="UTF-8" ?>
<record>
  <attribute id="0x0001">
    <sequence>
      <uuid value="0x1101"/>
    </sequence>
  </attribute>
  <attribute id="0x0004">
    <sequence>
      <sequence>
        <uuid value="0x0100"/>
      </sequence>
      <sequence>
        <uuid value="0x0003"/>
        <uint8 value="1" name="channel"/>
      </sequence>
    </sequence>
  </attribute>
  <attribute id="0x0100">
    <text value="Serial Port" name="name"/>
  </attribute>
</record>
"""

bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"),
                        "org.bluez.ProfileManager1")
manager.RegisterProfile("/bluez",
                        "00001101-0000-1000-8000-00805f9b34fb",
                        {"AutoConnect":True, "ServiceRecord":service_record})
while True:
    time.sleep(1)

2-2. Run the script.

python spp.py

2-3. Suspend the script by pressing Ctrl+Z.

 

3. Pairing
To establish a connection, Raspberry Pi and the phone need to be paired.

3-1. Launch bluetoothctl.

bluetoothctl

3-2. Enter below in order to be discovered from the phone.

discoverable on

3-3. On the phone, scan for Raspberry Pi and pair. You should be able to see something like below.

[CHG] Device XX:XX:XX:XX:XX:XX Paired: yes

3-4. Press Ctrl+D to quit.

 

4. Establishing Connection from Phone

4-1. Listen for incoming connection on Raspberry Pi.

sudo rfcomm watch hci0

4-2. Install and launch “Serial Bluetooth Terminal” app[5] on the phone.

4-3. In the app, go to “Device” menu and select Raspberry Pi. If everything goes well and the connection is established, you should be able to see like this:

$ sudo rfcomm watch hci0
Waiting for connection on channel 1
Connection from XX:XX:XX:XX:XX:XX to /dev/rfcomm0
Press CTRL-C for hangup

 

5. Connecting Serial Terminal on Raspberry Pi
5-1. Open another terminal and launch the serial terminal.

minicom -b 9600 -o -D /dev/rfcomm0

 

6. Test
6-1. Input some text on the phone.

You should be able to see the text on Raspberry Pi’s serial terminal.

6-2. Input some text back to the phone on Raspberry Pi.

You should be able to see the text on the phone.

 

References
[1] Serial_Port_Profile_(SPP) – Wikipedia
[2] minicom(1) – Linux man page
[3] Re: Bluetooth Python script. – Raspberry Pi Forum
[4] Tutorial: Creating a Bluetooth service
[5] Serial Bluetooth Terminal – Google Play

 

 

Setting Up Bluetooth Serial Port Profile on Raspberry Pi using sdptool

This post shows steps to set up Bluetooth Serial Port Profile (or SPP)[1] on Raspberry Pi.

The goal is to establish SPP connection between Raspberry Pi 3 and Android phone, then send/receive text using serial terminal applications on both ends.

SPP is not available by default. There are two options to enable it in BlueZ (which is the default Bluetooth stack in Linux). This post shows steps for the 1st option (sdptool).

  1. sdptool
  2. D-bus API (please see this post for this option)

 

Prerequisites (parentheses indicate my environment)

 

Steps
1. Installation
1-1. Install a serial terminal application on Raspberry Pi. In this post, I’ll use minicom[2].

sudo apt-get install minicom -y

 

2. Enable SPP on Raspberry Pi
In order to use SPP, Bluetooth service needs to be restarted with ‘compatibility’ flag[3].

2-1. Open Bluetooth service configuration file.

sudo nano /etc/systemd/system/dbus-org.bluez.service

2-2. Look for a line starts with “ExecStart” and add compatibility flag ‘-C’ at the end of the line.

ExecStart=/usr/lib/bluetooth/bluetoothd -C

2-3. Add a line below immediately after “ExecStart” line, then save and close the file.

ExecStartPost=/usr/bin/sdptool add SP

2-4. Reload the configuration file.

sudo systemctl daemon-reload

2-5. Restart the service.

sudo systemctl restart bluetooth.service

 

3. Pairing
To establish a connection, Raspberry Pi and the phone need to be paired.

3-1. Launch bluetoothctl.

bluetoothctl

3-2. Enter below in order to be discovered from the phone.

discoverable on

3-3. On the phone, scan for Raspberry Pi and pair. You should be able to see something like below.

[CHG] Device XX:XX:XX:XX:XX:XX Paired: yes

3-4. Press Ctrl+D to quit.

 

4. Establishing Connection from Phone

4-1. Listen for incoming connection on Raspberry Pi.

sudo rfcomm watch hci0

4-2. Install and launch “Serial Bluetooth Terminal” app[4] on the phone.

4-3. In the app, go to “Device” menu and select Raspberry Pi. If everything goes well and the connection is established, you should be able to see like this:

$ sudo rfcomm watch hci0
Waiting for connection on channel 1
Connection from XX:XX:XX:XX:XX:XX to /dev/rfcomm0
Press CTRL-C for hangup

 

5. Connecting Serial Terminal on Raspberry Pi
5-1. Open another terminal and launch the serial terminal.

minicom -b 9600 -o -D /dev/rfcomm0

 

6. Test
6-1. Input some text on the phone.

You should be able to see the text on Raspberry Pi’s serial terminal.

6-2. Input some text back to the phone on Raspberry Pi.

You should be able to see the text on the phone.

 

References
[1] Serial_Port_Profile_(SPP) – Wikipedia
[2] minicom(1) – Linux man page
[3] sdptool is broken in Bluez 5 – Arch Linux
[4] Serial Bluetooth Terminal – Google Play
[5] Bluetooth issues – Raspberry Pi Forum

 

 

Creating BLE GATT Server (UART Service) on Raspberry Pi


In this post, I will create BLE GATT server on Raspberry Pi 3 using BlueZ dbus interface with Python. I will reuse BlueZ example code as much as possible. As an example of GATT service, I’ll create UART service (a.k.a. Nordic UART Service/NUS [1] ), so that I can test it with Nordic’s smartphone app [2].

 

Assumptions

 

Steps
1. BlueZ Update
Raspbian Stretch comes with BlueZ 5.43. BlueZ’s Advertising Manager has been officially supported from 5.48. So, let’s update BlueZ by following this post.

 

2. UART Service Implementation
I’ll use “example-advertisement” and “example-gatt-server” from the downloaded source code in Step 1. Some of the classes and functions will be reused.

2-1. First, let’s create a working directory.

mkdir ble-uart-peripheral && cd ble-uart-peripheral

2-2. Copy the example code with new names so that they can be imported as modules.

cp ~/bluez-5.50/test/example-advertisement ./example_advertisement.py
cp ~/bluez-5.50/test/example-gatt-server ./example_gatt_server.py

Note: The file name of python module must have the suffix “.py” and should not have “-” (hyphen) in it.

2-3. Create a new file (e.g. “uart_peripheral.py”). I’ll reuse ‘Advertisement’ class, ‘Service’ class, ‘Characteristic’ class, and callback functions from the example code. Also, combine the both main() functions from the example code into one and modify the sub-classes of Advertisement, Application, Service, and Characteristic to realize the UART service.

import sys
import dbus, dbus.mainloop.glib
from gi.repository import GLib
from example_advertisement import Advertisement
from example_advertisement import register_ad_cb, register_ad_error_cb
from example_gatt_server import Service, Characteristic
from example_gatt_server import register_app_cb, register_app_error_cb

BLUEZ_SERVICE_NAME =           'org.bluez'
DBUS_OM_IFACE =                'org.freedesktop.DBus.ObjectManager'
LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1'
GATT_MANAGER_IFACE =           'org.bluez.GattManager1'
GATT_CHRC_IFACE =              'org.bluez.GattCharacteristic1'
UART_SERVICE_UUID =            '6e400001-b5a3-f393-e0a9-e50e24dcca9e'
UART_RX_CHARACTERISTIC_UUID =  '6e400002-b5a3-f393-e0a9-e50e24dcca9e'
UART_TX_CHARACTERISTIC_UUID =  '6e400003-b5a3-f393-e0a9-e50e24dcca9e'
LOCAL_NAME =                   'rpi-gatt-server'
mainloop = None

class TxCharacteristic(Characteristic):
    def __init__(self, bus, index, service):
        Characteristic.__init__(self, bus, index, UART_TX_CHARACTERISTIC_UUID,
                                ['notify'], service)
        self.notifying = False
        GLib.io_add_watch(sys.stdin, GLib.IO_IN, self.on_console_input)

    def on_console_input(self, fd, condition):
        s = fd.readline()
        if s.isspace():
            pass
        else:
            self.send_tx(s)
        return True

    def send_tx(self, s):
        if not self.notifying:
            return
        value = []
        for c in s:
            value.append(dbus.Byte(c.encode()))
        self.PropertiesChanged(GATT_CHRC_IFACE, {'Value': value}, [])

    def StartNotify(self):
        if self.notifying:
            return
        self.notifying = True

    def StopNotify(self):
        if not self.notifying:
            return
        self.notifying = False

class RxCharacteristic(Characteristic):
    def __init__(self, bus, index, service):
        Characteristic.__init__(self, bus, index, UART_RX_CHARACTERISTIC_UUID,
                                ['write'], service)

    def WriteValue(self, value, options):
        print('remote: {}'.format(bytearray(value).decode()))

class UartService(Service):
    def __init__(self, bus, index):
        Service.__init__(self, bus, index, UART_SERVICE_UUID, True)
        self.add_characteristic(TxCharacteristic(bus, 0, self))
        self.add_characteristic(RxCharacteristic(bus, 1, self))

class Application(dbus.service.Object):
    def __init__(self, bus):
        self.path = '/'
        self.services = []
        dbus.service.Object.__init__(self, bus, self.path)

    def get_path(self):
        return dbus.ObjectPath(self.path)

    def add_service(self, service):
        self.services.append(service)

    @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}')
    def GetManagedObjects(self):
        response = {}
        for service in self.services:
            response[service.get_path()] = service.get_properties()
            chrcs = service.get_characteristics()
            for chrc in chrcs:
                response[chrc.get_path()] = chrc.get_properties()
        return response

class UartApplication(Application):
    def __init__(self, bus):
        Application.__init__(self, bus)
        self.add_service(UartService(bus, 0))

class UartAdvertisement(Advertisement):
    def __init__(self, bus, index):
        Advertisement.__init__(self, bus, index, 'peripheral')
        self.add_service_uuid(UART_SERVICE_UUID)
        self.add_local_name(LOCAL_NAME)
        self.include_tx_power = True

def find_adapter(bus):
    remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
                               DBUS_OM_IFACE)
    objects = remote_om.GetManagedObjects()
    for o, props in objects.items():
        if LE_ADVERTISING_MANAGER_IFACE in props and GATT_MANAGER_IFACE in props:
            return o
        print('Skip adapter:', o)
    return None

def main():
    global mainloop
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
    bus = dbus.SystemBus()
    adapter = find_adapter(bus)
    if not adapter:
        print('BLE adapter not found')
        return

    service_manager = dbus.Interface(
                                bus.get_object(BLUEZ_SERVICE_NAME, adapter),
                                GATT_MANAGER_IFACE)
    ad_manager = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter),
                                LE_ADVERTISING_MANAGER_IFACE)

    app = UartApplication(bus)
    adv = UartAdvertisement(bus, 0)

    mainloop = GLib.MainLoop()

    service_manager.RegisterApplication(app.get_path(), {},
                                        reply_handler=register_app_cb,
                                        error_handler=register_app_error_cb)
    ad_manager.RegisterAdvertisement(adv.get_path(), {},
                                     reply_handler=register_ad_cb,
                                     error_handler=register_ad_error_cb)
    try:
        mainloop.run()
    except KeyboardInterrupt:
        adv.Release()

if __name__ == '__main__':
    main()

 

 

3. Test
3-1. Run the UART service on Raspberry Pi.

python uart_peripheral.py

If all goes well, the output should be like this. Now, the service is running on Raspberry Pi and it’s broadcasting BLE advertising message.
* See Troubleshoot when you get error.

$ python uart_peripheral.py 
GATT application registered
GetAll
returning props
Advertisement registered

3-2. Lauch nRF Toolbox app on the smartphone and tap on “UART”.

3-3. Tap on “CONNECT” button. Then the app will start scanning for nearby BLE devices.

3-4. Select your Raspberry Pi from the detected device list. It triggers the connection between the Raspberry Pi and the app.


 

 

 

 

 

* In case of iPhone, Raspberry Pi’s host name may be displayed instead of LOCAL_NAME in the code.

3-5. Tap on “Show Log”, enter some strings and tap on “Send”.

 

 

 

 

 

 

 

 

 

 

 

3-7. Check the console on Raspberry Pi. You should be able to see what you sent from the app like below.

remote: hello from iphone!

3-8. Let’s send back something from Raspberry Pi by entering below on Raspberry Pi’s console.

hello from Raspberry Pi!

3-9. Check the app screen.

 

 

 

 

 

 

 

 

 

 

 

 

 

Troubleshoot
If you are getting “Failed to register advertisement” error below, it’s most likely because the advertisement wasn’t unregistered when the script exited previously.

Failed to register advertisement: org.bluez.Error.Failed: Failed to register advertisement

An easy way to recover is to restart bluetooth service.

sudo systemctl restart bluetooth.service

 

 

References
[1] UART/Serial Port Emulation over BLE – Nordic Semiconductor 
[2] nRF Toolbox App – Nordic Semiconductor
[3] Turning a Raspberry Pi 3 into a Bluetooth Low Energy peripheral

 

 

Updating BlueZ on Raspberry Pi (from 5.43 to 5.50)


Update (Jul 9, 2019):
Now, Raspbian Buster, released on 6/20/2019, has bluez 5.50 by default!


This post shows how to update BlueZ on Raspberry Pi from 5.43 (the default version comes with Raspbian Stretch) to 5.50 (released notes [1]). In this post, I assume that you already have a Raspberry Pi 3 B+ or Raspberry Pi Zero W running Raspbian Stretch.

 

Steps [2]
1. Check Current BlueZ Version
1-1. Before starting, let’s check the current BlueZ version.

bluetoothctl -v

In case of Raspbian Stretch, the BlueZ version should be 5.43.

$ bluetoothctl -v
5.43

 

2. Install Dependencies
2-1. Update the package list.

sudo apt-get update

2-1. Install the dependencies.

sudo apt-get install libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev -y

 

3. Install BlueZ
3-1. Download BlueZ source code.

wget www.kernel.org/pub/linux/bluetooth/bluez-5.50.tar.xz

3-2. Uncompress the downloaded file.

tar xvf bluez-5.50.tar.xz && cd bluez-5.50

3-3. Configure.

./configure --prefix=/usr --mandir=/usr/share/man --sysconfdir=/etc --localstatedir=/var --enable-experimental 

3-4. Compile the source code.

make -j4

3-5. Install.

sudo make install

3-6. Reboot Raspberry Pi 3.

sudo reboot

 

4. Verify Update[3] [4]
4-1. Verify the BlueZ version by issuing the command below.

bluetoothctl -v

The result should be like this:

$ bluetoothctl -v
bluetoothctl: 5.50

 

References
[1] BlueZ Release Notes
[2] Installing Bluez 5.44 onto Raspbian? – Stack Exchange
[3] Bluetooth LE upgrade not working – Raspberry Pi Forum
[4] Why does bluetoothd show version 5.37 after installing Bluez 5.45? – Stack Exchange