There have been a lot of posts written about how to connect from Visual Studio Code (VS Code) on a Windows PC to a Raspberry PI over SSH using public/private keys avoiding the need to use a password. This is another one, and I aim to be fairly terse.
The PC is running Windows 11, the Raspberry Pi is running the latest version of Raspberry Pi OS – Debian Bullseye. Note that <username> is a placeholder for your own username, the greater than symbol: > represents a Windows PowerShell prompt and the dollar sign: $ is a Linux Bash prompt.
Setup The PI
SSH needs enabling on the PI and an ~/.ssh directory needs creating in your users home directory.
On the Pi, in the terminal enable SSH with: sudo raspi-config then select 3 Interface Options > I2 SSH and choose Yes – Enable. Now create the directory where your keys will be kept: mkdir ~/.ssh
It is also useful to find the IP address of your PI with: hostname -I Mine is 192.168.2.45 and I shall being using this in the examples.
You should now be able to login to the Pi from the Windows PC, open Windows Terminal or PowerShell and use ssh <username>@192.168.2.45 answer yes to add it to the known hosts file and it will ask for your PI’s password. If your Windows username is the same as that on the PI you can login with ssh 192.168.2.45.
Setup Windows for SSH
This stage installs the SSH client on the PC, creates a keypair and copied the public key to the PI.
The OpenSSH client can be installed using Windows Settings on Windows Server 2019 and Windows 10 and above devices.
Open Settings, select Apps > Apps & Features, then select Optional Features.
Scan the list to see if the OpenSSH is already installed. If not, at the top of the page, select Add a feature, then:
On the Windows PC, in your PowerShell create the directory for your keys if it doesn’t exist already mkdir ~/.ssh and then change into it cd ~/.ssh generate a keypair and add it to the ssh-agent:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>ssh-keygen-ted25519
Generating public/privateed25519 key pair.
Enter file inwhich tosave the key(C:\Users\<username>/.ssh/id_ed25519):
Enter passphrase(empty forno passphrase):
Enter same passphrase again:
Your identification has been saved inC:\Users\<username>/.ssh/id_ed25519.
Your publickey has been saved inC:\Users\<username>/.ssh/id_ed25519.pub.
And on the PI we need to add that public key to the authorized keys, connect into the PI ssh <username>@192.168.2.45 and:
1
2
3
4
5
$cd~/.ssh
$touch authorized_keys
$cat id_ed25519.pub>>authorized_keys
$chmod600authorized_keys
$rm id_ed25519.pub
the commands, touch creates a blank file if it doesn’t exist, cat appends the pub file to authorized_keys, making sure that any existing keys are preserved permissions are set with chmod and finally the pub file is deleted.
Setup VS Code
Load up VS Code and add the Remote – SSH and Remote SSH: Editing Configuration Files extensions, once restarted you will see a >< icon in the bottom left-hand corner with a green background, click that and select Edit SSH Configuration file…, choose the one in your home directory C:\Users\<username>\.ssh\config and add the following:
1
2
3
4
5
Host piComputer_192.168.2.45
HostName192.168.2.45
User<username>
ForwardAgent yes
IdentityFileC:/Users/<username>/.ssh/id_ed25519
The Host “piComputer_192.168.2.45” is the friendly name displayed within VS Code for when you are choosing it from lists, the User id your user on the PI. Save the config file when complete.
You should now be able to connect to the PI. Click the >< icon in the bottom left-hand corner, and choose Connect To Host… A popup saying Setting Up… should appear, it may ask if the host is Linux or Windows, choose Linux, and within a few seconds it’ll be connected and ready. From within VS Code you can open a Bash Terminal – Ctrl+Shift+’
If it asks for a password, you may have missed a stage, or copied the private key to the PI instead of the public one.
In this post I am setting up a network available RTSP video camera on a Raspberry Pi 4 Model B with the latest Debian Buster installed, you will also want another ‘remote’ computer with VLC installed on the same network. I have used a camera module connected via a ribbon cable to the Pi’s video port. The performance is more like what you would see from a security camera rather than some fancy dedicated device. I will be making the configuration with a bash shell using SSH rather than the GUI.
Installation
If you haven’t already, enable the camera on the Pi with sudo raspi-config and go to Interface Options > Camera. To reduce the load on the computer I also set the Pi to boot to the Console in System Options > Boot / Auto Login and selecting Console, you should also check that at least 256MB of memory is allocated to the GPU in Performance Options > GPU Memory, when complete reboot to set the updated configuration.
Install some prerequisites, you may have some or all of these installed already:
To setup V4L, edit the configuration file $ sudo nano /etc/uv4l/uv4l-raspicam.conf and update the driver options and uncomment the h264 options:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
##################################
# raspicam driver options
##################################
encoding=h264
#720p
width=1280
height=720
framerate=12
### h264 options:
profile=high
level=4.2
bitrate=8000000
intra-refresh-mode=dummy
intra-period=#arg
inline-headers=yes
sps-timing=no
quantisation-parameter#arg
Restart the service once you have saved the file:
1
$sudo service uv4l_raspicam restart
Useful screen Resolutions; designation, ratio: width x height:
1080p, 16:9: 1920 x 1080
720p, 16:9: 1280 x 720
720, 4:3: 1296 x 792
Standard Definition, 4:3: 640 x 480
I’ve chosen 720p 16:9 widescreen, this gives a good image quality without stressing the Pi 4B. The framerate is a compromise between quality and usability, its unlikely you would want to go above 25fps.
Connecting
If you don’t know it already, find the IP address of your Pi with $ ip a. Look for the address in eth0 or wlan0 depending on if you are using ethernet or wireless. In this case I will be using 192.168.2.33 in the examples.
Play thisstream using the URL"rtsp://192.168.2.33:8555/unicast"
Now on your ‘remote’ computer open VLC and choose Media > Open Network Stream and place the given stream address into the network URL, you will then be asked for the username and password. For me it took less than five seconds for an image to appear, there is a fairly high latency on the image shown, the picture lags by about a second from reality.
Using OpenCV
You can access the stream using Python scripts and OpenCV on your ‘remote’ computer for AI/Machine Learning. For me this is a Debian Linux box with FFmpeg as OpenCV uses this to access the stream.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/env python
import os
import cv2
# if the script doesn't work, uncomment the following, OpenCV may be
# defaulting to TCP when we are wanting to use UDP.
The Jetson Nano Developer kit – B01 is a small computer comprising of an NVIDA Maxwell GPU, Quad-Core ARM Cortex-A57 Processor and 4GB of Memory along with four USB 3 ports, Gigabit Ethernet, HDMI and Display Port output, main storage is on a MicroSD card and there is a variety of selection of expansion available via GPIO, I2C and UART. On the software side NVIDIA provide their JetPack SDK – a customised version of Ubuntu. This development kit has been produced to provide an entry point into Machine Learning, for which I will be using Python programming language. I got my board from Pimoroni
These notes cover my process of setting one up and links to the documentation, it not intended to repeat those install guides but to provide an install sequence and any additional commentary as needed. I’m going to assume you have a little experience of using the terminal and am familiar with using the bash command line – I’ve no idea how this would be done through the GUI.
Jetson Nano ports [source: NVIDIA]
Initial Startup
I followed the instructions for downloading and installing JetPack 4.4 on https://nvidia.com/jetsonnano-start I used a 64GB Class 10, UHS-I, U3, V30 SanDisk card. I formatted the card in a camera before using balenaEtcher to write the JetPack SDK image, this creates a partition of about 16GB on the card formatted to ext4, during installation the volume is resized to fill the card.
Jetson Nano connections [source: NVIDIA]
Despite using a good quality USB power supply with an output of 3 Amps at 5 Volts into the Micro USB port the computer would only boot long enough for the NVIDIA logo to appear on screen but after a few seconds the green power LED would go out and it would be off, the same happened when I tried a variety of USB power supplies used. I got round the problem buy using a 5 Amp power supply connected to the barrel jack J25 on the left (centre pin positive) and connecting the jumper J48 located just behind this connector.
Customising the Setup
There are a couple of thigs to do, get a network volume mounted and set the default version of python.
For the network share install samba, some network utilities and the nano text editor:
1
$sudo apt install samba cifs-utils nano
create a text file: sudo nano /etc/samaba/videoserver with the following:
1
2
username=<your network username>
password=<your network password>
And set the permissions sudo chmod 600 /etc/samba/videoserver. In this example I have a network share on my server; 192.168.1.30, called video. Create a mount point for the share: sudo mkdir /mnt/video now you need to edit fstab, sudo nano /etc/fstab and add your network connection to the end:
Reload fstab with sudo mount -a and check for any errors. Because of the way that Jetpack boots it does not appear to wait for the network so the share needs to be set to automount and this causes it to only appear in drive listings when accessed. Further reading can be found in this excellent guide to fstab: https://wiki.archlinux.org/index.php/fstab.
Jetpack 4.4 comes with two versions of Python, 2.7 and 3.6, I want it to default to 3.6 and while this is rather out of date I don’t want to go down the hole of upgrading just yet, you will also need to install pip and set pip3 as the default too.
I did get an error later on, a crash was reported on the desktop when an occasional python 2 script ran. I fixed the error in /usr/sbin/l4t_payload_updater_t210 by changing the first line of the file from !#/user/bin/python to !#/user/bin/python2
Post Install Problems
A recent update occured, so I did the usual sudo apt get update && sudo apt get upgrade but one of the files gave a script error, this turned out to be with nvidia-l4t-bootloader, like so:
Setting up nvidia-l4t-bootloader(32.4.3-20200924161615)...
3448-300---1--jetson-nano-qspi-sd-mmcblk0p1
Starting bootloader post-install procedure.
Update bootloader completed.
Reboot the target system forchanges totake effect.
Updating extlinux.conf...
Root device isset inthe extlinux.conf
Afterwards I set the default back to python 3.6 again.
Setup the Machine Learning
There are three Machine Learning packages, OpenCV for Computer Vison, Tensorflow for machine learning models, and TensorRT – accelerated deep learning networks for image recognition.
The Micro SD Card I use in a Raspberry PI ran out of space so here is how I copied the contents of the 15GB drive to a new 64GB card and resized the partition. I used a separate computer running Debian and as the machine does not have a monitor or keyboard attached this will be being completed through the bash command line using SSH.
1. Making a copy of the SD Card.
Insert the old card into your computer, if the computer attempts to mount the drive then unmount it. We need to find which mount point has been used, do this with the lsblk command:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda8:00477G0disk
├─sda18:10512M0part/boot/efi
├─sda28:20468.9G0part/
└─sda38:307.6G0part[SWAP]
sdb8:160477G0disk
└─sdb18:170477G0part/mnt/external_ssd
sdc8:3201.8T0disk
└─sdc18:3301.8T0part/data
sdd8:4803.7T0disk
└─sdd18:4903.7T0part/mnt/external_hdd
sde8:64114.9G0disk
├─sde18:65143.8M0part
└─sde28:66114.8G0part
The device sde matches our SD card. So we will use that. The dd command is used to create the ISO image, I am creating the file in my home directory:
The copied partition is now the same size as the original. If you have space remaining, the new card can be put back in the Pi and use the raspi-config utility, and using the Expand Filesystem option in the Advanced Settings section. However if the drive is completely full you won’t be able to login as there won’t be enough space available for the temporary files created at login, to get round this you can use parted to resize, start with:
1
$sudo parted/dev/sde
if you get the following message:
1
Warning:Unable toopen/dev/sde read-write(Read-only file system)./dev/sde has been opened read-only.
then quit from parted, if you are using a full size SD Card, check the Write Protect tab on the side of the card and try again, otherwise try:
1
2
3
4
5
$sudo hdparm-r0/dev/sde
/dev/sde:
setting readonly to0(off)
readonly=0(off)
If problem persists try formatting the new card in a camera, as these have a simple file system, and write the ISO image again.
We need to resize the larger partition /dev/sde2 with the ext4 file system, the smaller is used to boot the Pi and can be ignored. In parted, list the partitions with the print command:
1
2
3
4
5
6
7
8
9
10
11
$sudo parted/dev/sde
(parted)print
Model:Generic-USB3.0CRW-SD(scsi)
Disk/dev/sde:63.9GB
Sector size(logical/physical):512B/512B
Partition Table:msdos
Disk Flags:
Number Start EndSize Type File system Flags
14194kB50.1MB45.9MBprimary fat32 lba
250.3MB15.9GB15.9GBprimary ext4
Using resizepart set the new size, I set this to larger than the 15GB but smaller than the unallocated space, this to save me having to accurately work out the remaining space manually:
1
2
(parted)resizepart2
End?[15.9GB]?40GB
Now update the boundaries to grow and resize the partition into the freshly allocated space:
1
2
$sudo/sbin/e2fsck-f/dev/sde2
$sudo/sbin/resize2fs/dev/sde2
Now boot the Pi with the new card, login and use the raspi-config utility then in Advanced Options choose Expand Filesystem and follow the onscreen instructions. Once rebooted you should now be set to fill up your new card.
While extracting the telemetry data from the GoPro is reasonably well documented I have found some gaps for getting the extracting utilities installed and when extracting and combining data from multiple files. These notes are for a Debian/Ubuntu installation in a BASH Shell.
Installing the gopro-utils
As I couldn’t find any straightforward instructions for installation, I’ll be going through everything I needed to do to get it working, you may have some of these packages installed already.
1
2
3
sudo apt update
sudo apt upgrade
sudo apt install ffmpeg golang gpsbabel git
Now to get the gopro-utils and install them, I’m placing the source files into my Downloads directory, as well as the GPS data extractor we’ll be adding the other telemetry tools too, this is all a bit long winded.
go get github.com/JuanIrache/gopro-utils/telemetry
go get github.com/mlouielu/gpxgo/gpx
cd bin/gopro2gpx
go build gopro2gpx.go
sudo cp gopro2gpx/usr/local/bin/
cd../bin/gopro2geojson/
go build gopro2geojson.go
sudo cp gopro2geojson/usr/local/bin/
cd../gopro2json/
go build gopro2json.go
sudo cp gopro2json/usr/local/bin/
cd../gpmd2csv/
go build gpmd2csv.go
sudo cp gpmd2csv/usr/local/bin/
cd../gpmd2info/
go build gpmd2info.go
sudo cp gpmd2info/usr/local/bin/
cd../gps2kml/
go build gps2kml.go
sudo cp gps2kml/usr/local/bin/
Extracting the Data
You will need to find which stream in the video recording the data has been saved to, to find this use ffprobe to examine the recording and look for the stream that contains GoPro MET, for example:
You can see that what we are wanting is on stream 3, as far as I can tell this stays the same every time, I don’t know if it is different for other GoPro models.
This bash script extracts the GPS data in GPX format from all the GoPro GX recordings in the directory, other options have been commented out, if you are using Garmin VIRB edit there is also an option for use with that. The script creates two files, one that contains the raw data and another with the desired GPS data, the GPS output file has the same name as the recording, but in lowercase with a .gpx extension.
#gopro2gpx -i "$BINFILE" -a 200 -f 3 -o "$OUTFILE-virb.gpx"
#gopro2json -i "$BINFILE" -o "$OUTFILE.json"
done
Merging GPX files
As the GoPro splits recordings into 4GB blocks, when extracting you will get a single GPX file for each recording. Many pages found by Google say that to create a single track from these all you need to do is append the files into one big file. This is wrong, what you end up with is a single file with many short tracks, when what you are after is one long track covering the entire journey. This bash script uses gpsbabel to create single merged file from the extracted GPX data, it creates a file called “gpsoutput.gpx”.
FFmpeg is a command line program to manipulate, convert, record and stream video and audio, it is available for Mac, Linux and Windows. Here is a handy list of commands for reference, these have been tested with version 3.1.12 in a Debian Linux environment. I expect this list to grow over time as needs arise.
Using this codec reduces the time it takes for the video to be available after upload, however YouTube converts the file again to the VP9 codec and unless you have a popular channel, 100 subscribers or more, then this can take a few days or weeks and in the meantime your video can appear quite poor and blocky even when watching at 1080p, especially when there is a lot of movement like in a car dash-cam video. You can use FFmpeg to encode to VP9 webm format with this bash script:
This script is based on the encoding method shown in the WebM Wiki on my computer it is very slow and takes a quite a few hours to encode just nine minutes of video and the eventual results are so poor you’ll be wondering why you bothered.
• Convert to MP4 for use in Vegas Studio:
1
2
3
ffmpeg-iinputFile.mkv-codec copy outputFile.mp4
If you have a particularly old/odd video and get lots of pts has no value errors, then try this:
The -fflags +genpts option adds a Presentation Timestamp (PTS) to the frames, this must be before the -i as shown to work. Source.
• Set the video playback speed, this method adjusts the Presentation Timestamp (PTS) on each frame which may not work with older software. To slow down video divide the PTS by your required speed, this example slows the action by two times setpts=PTS/2.0. You can also reduce the number of dropped frames by increasing the frame-rate -r 50, in this case I went from 25fps to 50fps, but depending in the chosen speed frames may still be dropped.
• Concatenate Video Files
This combines two video files, when using formats such as MP4 or MKV you will need to create intermediate files, otherwise only the first file will be included in the output:
• The opus not found error
When converting a file and you see an error like Could not find tag for codec opus in stream #1… you will need to state the output format
Here is a small Bash script that converts any supported ffmpeg video format; such as .MKV, .MP4 or .MOV and extracts the audio to an .MP3 file, It will also split that MP3 file into chunks and put them in a convenient directory. You will need to install ffmpeg and mp3splt for your particular platform.
Example Usage:
mkv2mp3 example
Shell
1
./mkv2mp3"big fat file.mkv"
This uses ffmpeg to convert “big fat file.mkv” to “big fat file.mp3” and then uses mp3splt to create a directory “big fat file” containing the files 01 – big fat file.mp3, 02 – big fat file.mp3, etc. The MP3 files will be encoded at 128k Constant Bit Rate and each file will be around 50 minutes in length. To install in Debian/Ubuntu use: sudo apt-get install ffmpeg mp3splt
mp3splt can find the audio in a quiet region near where the split is desired rather than midway through a word, this should make for much cleaner playback across tracks.
Alternative Method
This script gives the same results but uses ffmpeg to split the large MP3 file and then adds track numbering metadata using id3v2. To install in Debian/Ubuntu use: sudo apt-get install ffmpeg id3v2
Taking this further, I was thinking that it would be nice to have these converted into the M4B Audiobook format for use on my elderly iPod. The script below assumes that you have processed the files as above and have added metadata tags using a tool like mp3tag (yes I know this is for Windows).
To complete this we need to: Combine the multiple MP3 files into one big file, or read the original big file then convert that to M4B format at 96K bit and add chapter marks every ten minutes. For this I have used ffmpeg v3.2.12 and libmp4v2 (for the mp4chaps utility), to install in Debian/Ubuntu use: sudo apt-get install libmp4v2-dev mp4v2-utils ffmpeg
This script works best from a single MP3 file rather than from those that have been re-combined back into a single file, recombining the files caused ffmpeg to exclaim “invalid packet size” and “invalid data” errors. It is able to tell the difference between a directory and a single MP3 and processes the file accordingly, don’t forget to add metadata tags and cover art before you run the script.
mp3tom4b
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/bin/bash
INFILE="$1"
BITRATE="96k"
MP3TITLE=""
MP3ARTIST=""
MP3ALBUM=""
MP3COMMENT=""
MP3YEAR=""
MP3PERFORMER=""
####
#### FUNCTIONS
####
functionsetMP3variables(){
TAG="$1"
VALUE="$2"
case"$TAG"in
title)
MP3TITLE="$VALUE"
;;
artist)
MP3ARTIST="$VALUE"
;;
comment)
MP3COMMENT="$VALUE"
;;
album_artist)
MP3PERFORMER="$VALUE"
;;
album)
MP3ALBUM="$VALUE"
;;
date)
MP3YEAR="$VALUE"
;;
esac
}
## get the tag text from the metadata
## if the line contains an equals (=) then split by the first equals.
functiongetMP3tags(){
MP3METADATA="$1"
whileread-rline
do
case"$line"in
*=*)
TAG=${line%%"="*}
VALUE=${line#*"="}
setMP3variables"$TAG""$VALUE"
;;
esac
done<"$MP3METADATA"
if[[!-z"${MP3TITLE// }"]];then
OUTFILE="$MP3TITLE".mp3
M4BFILE="$MP3TITLE".m4b
fi
}
####
#### BEGINS
####
FILENAME=$(basename"$INFILE"|cut-d.-f1)
if[[-z"${FILENAME// }"]];then
echo"filename missing"
exit1
fi
OLDIFS=$IFS
OUTFILE="$FILENAME"_out.mp3
M4BFILE="${OUTFILE:0:-4}".m4b
METADATA="${OUTFILE:0:-4}".metadata
JPGFILE="${OUTFILE:0:-4}".jpg
## check if input is a diretory
if[-d"$INFILE"];then
# get the name of the first MP3 file in the directory
These appear to be caused by the mp3splt program from when the original MP3 file was being split into 50 minute chunks, but I can’t hear any effect on the output.
Lots of information about the file can be gotten using mediainfo, to install in Debian/Ubuntu use: sudo apt-get install mediainfo, example use:
Bluetooth Low Energy – BLE – Bluetooth 4.0 is an industry-standard wireless protocol built for the Internet of Things – IoT, it is designed to provide connectivity for devices operating from low capacity power sources such as coin cell batteries.
Raspberry Pi2 with ASUS USB-BT400 Bluetooth 4.0 Dongle
In this introduction to BLE I’ll be configuring a Raspberry Pi2 computer to talk to a smart watch. We will be installing the latest version of BlueZ from source, enabling BLE support. This is not a tutorial on decoding the data from the watch I am just using it as an example, although I may write about decoding it in a future posting.
I am using a ASUS USB-BT400 Bluetooth 4.0 Dongle on a Raspberry Pi2 but this will work on any computer with a Debian based distribution. Your dongle must be BLE/Bluetooth 4.0 capable otherwise this won’t work. I am using an ID107HR activity tracker with pedometer and heart rate monitor, randomly chosen from the list of cheap ones available on Amazon. While using the Pi to talk to the the watch make sure Bluetooth on the phone is off as it can only connect to one device at a time.
The current distribution of Raspbian – jessie on the Raspberry Pi comes with version 5.23 of the BlueZ Bluetooth stack that’s rather old, dating from September 2014 which lacks many of the features we will be needing. The current version 5.44 of the BlueZ has many changes in the package with many familiar components such as hcitool and gatttool being depreciated, so I will be ignoring those and using the available commands, bluetoothctl, on the terminal.
Installing BlueZ
With Raspbian – jessie installed we will need to update the Pi make sure some packages are installed and then installing the latest version of BlueZ. But first, remove the installed version 5.23 of BlueZ:
removing the installed bluez
1
2
$sudo apt-get--purge remove bluez
$sudo apt-get autoremove
Next, perform the traditional housekeeping updates then install the build tools and USB libraries. Those parts that are installed already will be automatically skipped.
Inside the BlueZ directory, configure, make (this takes a while), and install. The experimental option adds BLE support and enabling the library allows for python use later on:
installing bluez
1
2
3
$./configure--enable-experimental--enable-library
$make
$sudo make install
Configuring and Starting BlueZ
At this stage we will need to check that the installation worked and that we can see your bluetooth dongle. With your bluetooth dongle in a USB port you should see it on your list of USB devices, here you see mine as device ID: 0b05:17cb ASUSTek Computer, Inc.:
dongle view
1
2
3
4
5
6
$lsusb
Bus001Device006:ID0b05:17cbASUSTek Computer,Inc.
Bus001Device004:ID046d:c52e Logitech,Inc.
Bus001Device003:ID0424:ec00 Standard Microsystems Corp.SMSC9512/9514Fast Ethernet Adapter
You will also need to enable the experimental services, edit the file /lib/systemd/system/bluetooth.service and in the [Service] section change the ExecStart line to end with –experimental:
for first time use, try scanning to find your watch, if it doesn’t appear it is out of range, its battery is flat, or your dongle does not support BLE, here you can see it as ID107 HR:
bluetoothctl remembers your devices, so when you next use the program the watch appears on the list at the start. The controller has a number of options, these can be seen with help command. You can use show to view the status of your dongle:
UUID:A/VRemote Control Target(0000110c-0000-1000-8000-00805f9b34fb)
Modalias:usb:v1D6Bp0246d052C
Discovering:no
The list of UUID’s show the services supported by the Dongle. Now we can power the dongle on, set the agent – this manages the connection, and then connect to the watch on which the bluetooth symbol will appear. Once connected there will be a pause then you will see a list of attributes supported by the watch, it is advertising the services available:
These UUID’s are used to describe the sevices available on the device, some are pre-defined and can be found in the a href=”https://www.bluetooth.com/specifications/gatt/characteristics” target=”_blank” rel=”noopener noreferrer”>GATT schema, others are vendor specific and unless they publicly release these, decoding can become rather difficult. There are four types of attribute:
Services – collections of characteristics and relationships to other services that encapsulate the behavior of part of a device
Characteristics – attribute types that contain a single logical value
Descriptors – defined attributes that describe a characteristic value
Declarations – defined GATT profile attribute types
Each attribute is identified by a 128 bit ID, for example, one of the characteristics from the list above: 00002902-0000-1000-8000-00805f9b34fb, the first eight bits are used as an unique identifier: 00002902 and are shown as UUID’s: 0x2902. Data is contained in services, each service has a number of characteristics that may contain further descriptions depending on the requirement of the characteristic. You can see how the data is mapped out in this chart:
Service Containers
A spreadsheet with the watch data reformatted and tastefully coloured to illustrates this. Observe the Service URL column, it looks a lot like a directory structure:
Here we see two services /service0008 and /service000c looking further into the second service: /service000c we see that it has four characteristics, and to of those have descriptors. We can interrogate the characteristics and descriptors to glean further information by selecting the attribute and reading, like so:
Which is all very nice, but not particularly helpful as the manufacturer has chosen to use custom, proprietary, UUID’s for the watch. We don’t know the instructions to send to have the watch realease its data.
Those Scripting BlueZ
Inevitably, you’ll be wanting to automate connections. This becomes easy with the automation scripting language expect. Install, then make a script file:
install expect
1
2
3
4
$sudo apt-get install expect
$cd~
$nano bttest
$chmod+xbttest
In this example the script forgets the watch, finds the watch, connects to the watch, gets some info and then disconnects:
expect
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/usr/bin/expect -f
set timeout10
set prompt".*#"
set usrpasswd""
set address"C5:E8:FB:BF:F2:6C"
## execute blutetoothctl
spawn sudo bluetoothctl
expect-re".*password.*"
send"$usrpasswd\r"
## forget about the device - if connected previously
expect-re$prompt
send"remove $address\r"
expect-re$prompt
sleep3
## switch on the dongle
send"power on\r"
expect"Changing power on succeeded"
expect-re$prompt
## scan for devices
send"scan on\r"
expect-re$prompt
sleep5
send"scan off\r"
expect-re$prompt
## set the agent
send"agent on\r"
expect"Agent registered"
send"default-agent\r"
expect-re$prompt
sleep2
## connect to watch
send"connect $address\r"
expect-re$prompt
## get some info
send"info $address\r"
expect-re$prompt
## disconnect
send"disconnect $address\r"
sleep2
expect-re"\[bluetooth\]#"
## bye
send"exit\r"
in the script, send sends a command, don’t forget to add the carriage return – \r and expect is used to wait for a response within the timeout period, here it is set to 10 seconds. expect -re is using regex when looking for a reply, otherwise it uses a literal string. So much more can be done with expect and there are many tutorials, such as this one written by FluidBank.
More Bluetooth Data
For analysing bluetooth data a couple of very useful tools are available, Wireshark and Android data logging. I will go through the installation but not look at the data in any detail, this posting is getting a bit long. This Section is in two parts, installing Wireshark and Android Debug Bridge.
Sniffing with the Shark
Wireshark is a network and bluetooth packet sniffer, it shows you network and bluetooth traffic occurring on your Pi. Here is a quick installation method for a reasonably new version of Wireshark (v2.2.4) from the backports, answer yes to the question “Should non-superusers be able to capture packets?”:
and if you get a message about permissions, reconfigure the package and answer yes:
wireshark install
1
$sudo dpkg-reconfigure wireshark-common
Start Wireshark and double click your bluetooth device on the list, in my case bluetooth0. There is not much to see as Wireshark will only see traffic between the watch and the Pi:
Wireshark Data Capture
Android Debug Bridge – ADB
For Anroid 4.2.2 and above, activate developer mode on the phone, go to Settings, tap About Phone and at the bottom of the list tap Build Number three times. Back in the main settings page Developer Options has appeared, tap developer and turn USB debugging On. With the phone plugged into a USB port a little Android head should appear in the information bar at the top-left of the screen. To begin we will need to install some udev rules written by Nicolas Bernaerts:
At this point on the phone an allow USB debugging dialog will appear, give permission and always trust to authorise it. ADB will now show the device as a device:
android tools install
1
2
3
$adb devices
List of devices attached
064be417008eef9fdevice
If the device list is empty, with everything plugged in good and proper and the phone setup in developer mode, start your diagnosis by checking udev; open another terminal window and view logging with udevadm monitor –environment and reload with sudo udevadm control –reload I’m not entirely sure what I did to get it from ‘not working’ to ‘working’. If all else fails elevate yourself to root.
Data Capture
With ADB now setup we can capture the Bluetooth data being exchanged. With bluetooth off, in the Developer Settings find Enable Bluetooth HCI snoop log and turn it On. In the smartwatch app synchronise with your watch, once complete turn Bluetooth off manually – this is to minimise the amount of captured data. Don’t forget to turn logging off on the phone when done. To find where the log file has been stored and copy the file from the phone to the Pi use:
This wasn’t quite the posting I originally had in mind, I wanted to decode the data from the watch for my own use, making something more useful, impressive graphs and charts, than that provided by the Android App VeryFit 2.0 but as the manufacturer has chosen to use proprietary GATT codes it makes the job that much harder. It may be much simpler to just buy an expensive FitBit and download the data from them. But with writing this I now know a few things that were previously unknown, and I hope that this has provided some light to your BlueZ (a pun!, right at the end!).
This is a follow up to one of my previous postings: Python and the Oracle Client. The main databases here are being upgraded to Oracle 12 and I’ve taken the opportunity to update the client used by my Python scripts, also its good practice to install new clients when old versions go out of support.
Current Setup
The system I am upgrading here has the following configuration, but this should work with any RPM based distribution, such as CentOS and SUSE :
Red Hat Enterprise Linux Server release 6.6 (Santiago)
To find the versions of your currently installed software: $ python
Python 2.6.6 (r266:84292, Nov 21 2013, 10:50:32)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cx_Oracle
>>> print cx_Oracle.version
5.1.2
and the Oracle client: $ rpm -qa | grep oracle
oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64
oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64
Preparing
If you have the old versions installed you will need to do some tidying up by removing the client and python connector, version 11 of the client despite being RPM packaged had some non-standard elements. Use rpm to delete the old version of instant client, remove devel first: $ sudo su
# rpm -ev oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64
# rpm -ev oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64
you may also need to remove the library reference from a previous installation: # rm /etc/ld.so.conf.d/oracle.conf
# ldconfig
to remove the Python oracle connector, there are two methods. Manually, by finding the previously installed package deleting the files and editing the package list: # find / -name cx_Oracle.py -print
/usr/lib/python2.6/site-packages/cx_Oracle-5.1.2-py2.6-linux-x86_64.egg/cx_Oracle.py
# cd /usr/lib/python2.6/site-packages
# rm -rf cx_Oracle-5.1.2-py2.6-linux-x86_64.egg
now edit the easy-install.pth file # nano /usr/lib/python2.6/site-packages/easy-install.pth
and remove the line: ./cx_Oracle-5.1.2-py2.6-linux-x86_64.egg
Or do it the easy way, if you have pip installed: # sudo pip uninstall cx_Oracle
easy_install does not have an uninstall option.
Installing
Download and install version 12 of the Instant Client and SDK (devel), these can be gotten from: http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html For Linux choose the correct flavour for your installed operating system: x86 or x86-64 for 64bit operating systems, you will need to register on the site gain access the files. # rpm -i oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm
# rpm -i oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm
Now to install the python connector: # easy_install cx-Oracle
or, the recommended method: # pip install cx-Oracle
Installation for the version 12 client is much more straight forward than that for version 11.
Testing
A quick test to ensure that the expected versions appear, and that you can connect to the database. Python 2.6.6 (r266:84292, Nov 21 2013, 10:50:32)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cx_Oracle
>>> cx_Oracle.version
'5.2'
>>> oraConn = "<USERNAME>/<PASSWORD>@<DATABASE HOST>:<DATABASE PORT>/<SERVICE>"
>>> ocDB = cx_Oracle.connect(oraConn)
>>> ocDB.version
'12.1.0.2.0'
Update: 15 April 2016 – Added information about which IP address to use and assigning static IP addresses for printers and servers
Recently I have needed to find an emergency alternative to my broadband due to the regional wide area network, Digital Region, being shut down, and the ISP Origin making a mess of getting all their cutomers onto ASDL. To get quickly back onto the internet, I have bought an ZTE MF823 4G Mobile Broadband Dongle as supplied by the badly named ‘three’ mobile phone company. As I have my own internal wired network, with multiple computers and ‘things’ there is a need to have something more sophisticated than just plugging the dongle into a single PC.
Here is my recipe for setting up a Raspberry Pi as a router with an ZTE MF283 Dongle. In this setup all the computers are on a wired Ethernet connection using a switch for the network. The Pi has Raspbian Debian Wheezy installed (June 2014) with all the latest updates made. For testing, the dongle is plugged into the USB port via a powered hub, and the Pi connected to a switch with another PC running Linux Mint.
Which IP addresses to use?
In this How-To I am using the IP address range 192.168.2.xxx this is to avoid conflict with the cable router which uses the 192.168.1.xxx range (the DHCP server is switched off on the router). IPv4 addresses are split into three different ranges, the 192.168.xxx.xxx range – 192.168.0.0 to 192.168.255.255 gives a possible 65,536 addresses but for your home it is unlikely you’ll have more than 255 network devices, so we can simplify things by limiting the address range used to 192.168.2.xxx and avoid the troublesome world of subnet masking.
192.168.xxx.xxx is used as its been designated for use on private networks by the Internet Assigned Numbers Authority this is a well established convention and is best practice. Two other IPv4 address ranges are available for larger private networks: 172.16.0.0-172.31.255.255 and 10.0.0.0-10.255.255.255 with 1,048,576 and 16,777,216 available addresses respectively, the most suitable network class should be chosen for your network.
Setup the Dongle
This USB dongle has its own built in dialer so you do not need ppp or wvdial installed, it appears as a USB ethernet device on the Raspberry Pi. You will need a powered USB hub as the dongle can draw more power than the Pi can provide, the symptoms of too much of power being drawn will be the Pi behaving erratically or restarting unexpectedly.
With the dongle plugged in, check that it is recognised by the Pi with lsusb, it can be seen here as ‘ZTE WCDMA Technologies MSM’:
The device ID is 19d2. and 1405 is the mode, this should be 1405 – CDC ethernet. If it is not, try removing the micro-SD card and rebooting the Pi, the device modes available are:
1225 – Default mode. USB Mass Storage Device + CD-ROM + card reader.
1403 – Modem mode. RNDIS + Mass Storage Device.
1405 – CDC ethernet
0016 – Download mode
As the dongle also has a Mass Storage Device the Raspberry may not switch to CDC ethernet. If the mode does not change, try the following with usb-modeswitch: $ sudo apt-get install usb-modeswitch
$ sudo usb_modeswitch -v 0x19d2 -p 0x1405 -d
I did not have to change the mode as it was correct already, and it didn’t change when I tried setting it as a Mass Storage device, I have not explored this any further.
When first plugged in the dongle was recognised as a ethernet device but it did not obtain an IP address:
ifconfig
Shell
1
2
3
4
5
6
7
$ifconfig
usb0Linkencap:Ethernet HWaddr36:4b:53:b7:e3:6e
UP BROADCAST RUNNING MULTICAST MTU:1500Metric:1
RX packets:0errors:0dropped:0overruns:0frame:0
TX packets:0errors:0dropped:0overruns:0carrier:0
collisions:0txqueuelen:1000
RX bytes:0(0.0B)TX bytes:0(0.0B)
if this is the case with you, add the following two lines to the end of sudo nano /etc/network/interfaces: auto usb0
iface usb0 inet dhcp
the dongle provides its own address to the computer. Reboot, and you should see the obtained address:
The address 192.168.0.185 is now the internet address of the computer the dongle always assigns this address, there is also a useful web status page on http://192.168.0.1
Configuring the network
first of all enable ip4 forwarding, edit the file sudo nano /etc/sysctl.conf and uncomment the line: net.ipv4.ip_forward=1
this will enable forwarding on reboot, you can also enable IP forwarding immediately with: $ sudo sysctl -w net.ipv4.ip_forward=1
We now need to give the Pi a static IP address on the internal network. Edit sudo nano /etc/network/interfaces so you end up with a file that looks like this:
interfaces
Shell
1
2
3
4
5
6
7
8
9
10
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address192.168.2.1
netmask255.255.255.0
auto usb0
iface usb0 inet dhcp
this gives the Pi a static IP address of 192.168.2.1.
DHCP
The next stage is to give the other computers on your network an IP address, this is done with a dhcp server: $ sudo apt-get install isc-dhcp-server
you will need to configure dhcp sudo nano /etc/dhcp/dhcpd.conf, here is mine:
dhcpd.conf
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
default-lease-time600;
max-lease-time7200;
ddns-update-style none;
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
# give your network printer and file server a static IP addresses
hostprinter1{
hardware ethernet08:00:2b:4c:59:23;
fixed-address192.168.2.45;
}
hostfileserver{
hardware ethernet12:20:cb:3c:32:4d;
fixed-address192.168.2.40;
}
This will assign IP addresses in the range 192.168.2.50 to 192.168.2.150 to any computer connected to your network. I have used Open DNS for the Domain name Servers, if you wish to use google’s use: option domain-name-servers 8.8.8.8, 8.8.4.4;instead.
I have also given my network printer a static IP address, it is still assigned by the DHCP server but never changes, the same would apply to any file servers and the like, I would assign static devices addresses that are outside your dynamically assigned range. Reboot the Pi and then your test computer.
Your test computer should now have an IP address (192.168.2.51), and the gateway point to the Pi (92.168.2.1):
The final part is to have the incoming traffic on the the Ethernet port eth0, go out on the dongle usb0. This is achieved with iptables, a firewall and traffic router. Install with: $ sudo apt-get install iptables
and you need to setup Network Address Translation, NAT and forwarding. This short bash script clears any old settings before applying the new rules:
Where LAN is your internal network, and WAN is the internet. The final line allows you access to the Dongle’s built in web status page from any browser on your internal network, just use: http://192.168.2.1:2525
Save the file in your home directory as ~/ipt.sh, make it executable and run the script.
$ chmod +x ~/ipt.sh
$ sudo ~/ipt.sh
From your test computer, you will now be able to access the internet.
Finally, you now need to have iptables reload when you start the Pi. Export the iptables settings to a file with:
$ sudo sh -c "iptables-save > /etc/iptables.ipv4.nat"
and create a file sudo nano /etc/network/if-up.d/iptables with the following contents:
iptables
Shell
1
2
#!/bin/bash
/sbin/iptables-restore</etc/iptables.ipv4.nat
and make it executable sudo chmod +x /etc/network/if-up.d/iptables
after a reboot you can see your iptables with sudo iptables -L and sudo iptables -t nat -L and you can see web traffic passing through the router with sudo tcpdump -i any -nn port 80.
Adding a Proxy Server
This is optional, but a transparent proxy server and cache may reduce the amount of traffic on your 3G/4G connection, mileage varies and the amount of data cached was less than I thought it would be, I also found that my Humax Freesat box really didn’t like the proxy server and wouldn’t update its TV schedules while it was on. I have used squid3 for this. sudo apt-get install squid3
Update the squid3 configuration /etc/squid3/squid.conf so it has the following. The original is rather large, so you may want to make a copy and create a new one:
then restart squid3 sudo /etc/init.d squid3 restart
add the following iptables rule to redirect all traffic on port 80 to squid3: iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3128
you should now be able to watch the web traffic being processed through squid3 with: sudo tail /var/log/squid3/access.log -f
finish off by exporting your iptables again, so they are reloaded on reboot: sudo sh -c "iptables-save > /etc/iptables.ipv4.nat" Raspberry Pi as 4G Router