Using Supervisord and tmpfs ramdisks on a Raspberry Pi

The Supervisor daemon is an easy to use utility which makes sure your services are running and never stop. It has its own logging infrastructure which you can check when things go wrong, aside of your own logging infrastructure. However, logging can degrade the SD card on embedded Raspberry Pi systems. Tmpfs to the resque!

Tmpfs allows us to make a filesystem in RAM so that no write cycli is made on the SD card. It can easily be made be editing /etc/fstab:

sudo vim /etc/fstab

And add:

tmpfs /var/log tmpfs defaults,noatime,mode=0755 0 0

When you reboot your system the content of /var/log, where all log messages are usually found, is now stored on the RAM based filesystem, hence improving SD card lifetime.

Enter Supervisor. To install supervisor:

sudo apt-get install supervisor

Configure your service by editing /etc/supervisor/conf.d/, for example I have a service running in Mono so I edit /etc/supervisor/conf.d/shutterservice.conf. Inside you’ll find following content:

[program:shutterservice]
command=mono /var/www/shutterservice/ShutterService.exe -d
user=www-data
stderr_logfile = /var/log/supervisor/shutterservice-err.log
stdout_logfile = /var/log/supervisor/shutterservice-stdout.log
directory=/var/www/shutterservice/

When you reboot your system again you’ll find that your service might not be available. You can verify this be starting and stopping the service by hand using supervisorctl. This tool will generate some obscure errors at this stage.

The problem here is that the supervisor daemon was not able to create its /var/log/supervisor logging directory when the system boots. You may create the directory yourself and restart supervisor manually using:

sudo mkdir /var/log/supervisor
sudo service supervisor restart

This time supervisor should be able to start, double check the logging files to make sure. However when you reboot your Pi again the tmpfs system will be cleared again, and once again supervisor will not be able to start automatically because of the missing log folder. We can fix this by using a config file for systemd which automatically creates temporary files.

Go ahead and create this config file:

sudo vim /etc/tmpfiles.d/supervisor.conf

Enter following content:

d /var/log/supervisor 0777 root root

When you reboot your system everything should be working as expected, plus you have just extended your SD card’s lifetime!

Advertisements

Creating an IoT thermostat (part III)

Improving our Yocto based distribution

Intro

Previously we made ourselves a Linux distribution ourselves for our target embedded system. We included basic Qt5 support which allows us to create a fast and responsive C++ frontend. This time we will further develop our embedded system and prepare it for usage.

Adding QtQuick – QML support

In the previous article we succeeded in created a QtWidget based application. However, with QtQuick there is a new UI framework available which has its own set of benefits. You may already have noticed that QtCreator comes with lots of examples and you may have even tried some of them. However, if you (like me) created your Yocto based OS using the bitbake qt5-basic-image command you will find that some programs may not work when yo run them on your embedded device:

root@raspberryyocto:~# ./clocks
./clocks: error while loading shared libraries: libQt5Quick.so.5: cannot open shared object file: No such file or directory
root@raspberryyocto:~#

Basically we didn’t include support for QtQuick when we compiled our OS. So if you’re into using QtQuick go back through your Yocto working folder and bitbake the qt5-image:

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$ bitbake qt5-image
Loading cache: 100% |############################################| Time: 0:00:00
Loaded 2660 entries from dependency cache.
Parsing recipes: 100% |##########################################| Time: 0:00:01
Parsing of 1972 .bb files complete (1964 cached, 8 parsed). 2668 targets, 353 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION = "1.32.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "arm-poky-linux-gnueabi"
MACHINE = "raspberrypi"
DISTRO = "poky"
DISTRO_VERSION = "2.2.1"
TUNE_FEATURES = "arm armv6 vfp arm1176jzfs callconvention-hard"
TARGET_FPU = "hard"
meta
meta-poky = "morty:a3fa5ce87619e81d7acfa43340dd18d8f2b2d7dc"
meta-oe
meta-multimedia
meta-networking
meta-python = "morty:1efa5d623bc64659b57389e50be2568b1355d5f7"
meta-qt5 = "morty:9aa870eecf6dc7a87678393bd55b97e21033ab48"
meta-raspberrypi = "master:e1f69daa805cb02ddd123ae2d4d48035cb5b41d0"
meta-rpi = "morty:03841471ccaed549a2a14a896c13f71af76cf482"

Initialising tasks: 100% |#######################################| Time: 0:00:08
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 3619 tasks of which 3538 didn't need to be rerun and all succeeded.
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$

Notice how fast compiling the image goes this time compared to when we build the qt5-basic-image. The reason for this faster build time is because the qt5-image inherits the qt5-basic-image and Yocto just needed to recompile some of the components that were not yet compiled. Also note that you don’t need a new SDK and you shouldn’t need to re-configure QtCreator.

With your SD card already formatted you only need to copy the compiled files to your SD card:

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$ cd ../meta-rpi/scripts/
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ sudo umount /dev/mmcblk0p1
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ sudo umount /dev/mmcblk0p2
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ export MACHINE=raspberrypi
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ export OETMP=/media/geoffrey/Data/yocto-pi/rpi/build/tmp
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ ./copy_rootfs.sh mmcblk0 qt5 raspberryyocto

OETMP: /media/geoffrey/Data/yocto-pi/rpi/build/tmp
IMAGE: qt5
HOSTNAME: raspberryyocto

File found: /media/geoffrey/Data/yocto-pi/rpi/build/tmp/deploy/images/raspberrypi/qt5-image-raspberrypi.tar.xz

Block device not found: /dev/mmcblk02, trying p2

Formatting /dev/mmcblk0p2 as ext4
[sudo] wachtwoord voor geoffrey:
/dev/mmcblk0p2 bevat een ext4-bestandssysteem met label 'ROOT'
laatst aangekoppeld op / op Sun Feb 19 22:07:51 2017
Toch doorgaan? (j,n) j
Mounting /dev/mmcblk0p2
Extracting qt5-image-raspberrypi.tar.xz to /media/card
Writing raspberryyocto to /etc/hostname
Unmounting /dev/mmcblk0p2
Done
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$

With that done we need to have a QtQuick test application. If you haven’t yet tried on of the QtCreator’s QtQuick examples do so now. Get back to your embedded device, insert the SD card and boot. Once booted, retrieve the device’s IP address and copy over any QtQuick test application. I’ve used the clocks application. Once you have the application compiled and copied over to the raspberry pi, ssh into your pi and start the application (or launch it from within QtCreator if you’ve had it still openened). You should see more or less something like this:

qtquick-demo-clocks-small

If you happen to run into “out of memory” errors:

root@raspberryyocto:~# ./clocks
QML debugging is enabled. Only use this in a safe environment.
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).
JIT is disabled for QML. Property bindings and animations will be very slow. Visit https://wiki.qt.io/V4 to learn about possible solutions for your platform.
glGetError 0x505
QSGTextureAtlas: texture atlas allocation failed, out of memory

… then you should tweak the CPU/GPU memory allocation settings. This settings is loaded at boot and it is also saved in a config file on your boot partition. To adjust the config file we first need to mount the boot partition, and next we can edit the file using the vi editor:

root@raspberryyocto:~# mkdir /mnt/fat
root@raspberryyocto:~# mount /dev/mmcblk0p1 /mnt/fat
root@raspberryyocto:~# vi /mnt/fat/config.txt

Add gpu_mem=256 to this file and reboot your pi. Try again running the clocks application, things should go now as intended:

root@raspberryyocto:~# ./clocks
QML debugging is enabled. Only use this in a safe environment.
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).
JIT is disabled for QML. Property bindings and animations will be very slow. Visit https://wiki.qt.io/V4 to learn about possible solutions for your platform.

Setting the timezone

To show the current time we will rely on NTP. RaspberryPi does not come with a RTC see I don’t see any other option. NTP is already added via Yocto, we only have to set the correct timezone:

root@yoctopi:~# ls -l /etc/localtime
lrwxrwxrwx 1 root root 27 Apr 10 18:36 /etc/localtime -> /usr/share/zoneinfo/EST5EDT
root@yoctopi:~# rm /etc/localtime
root@yoctopi:~# ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime
root@yoctopi:~# date
Sun Apr 16 12:30:40 CEST 2017

Adding a touch screen

The RaspberryPi community has a very decent 7″ touch screen. There is not much to say about, I got one, followed the instructions to hook it op and basically started testing some my applications straight away!

2033-01

Side note: I used the same housing as show above. This one has the display upside down, the rotate the display through software we must again edit the config file on the boot partition:

root@raspberryyocto:~# mkdir /mnt/fat
root@raspberryyocto:~# mount /dev/mmcblk0p1 /mnt/fat
root@raspberryyocto:~# vi /mnt/fat/config.txt

and add:

display_rotate=2

Restart to apply your changes.

Adding a HTU21D I²C temperature sensor

The HTU21D is a decent temperature and humidity sensor which perfectly suits our needs. To hook it up to our Raspberry Pi 2:

htu21d-block-s

Before we can use the I2C bus we must again edit the Pi’s config file:

root@raspberryyocto:~# mkdir /mnt/fat
root@raspberryyocto:~# mount /dev/mmcblk0p1 /mnt/fat
root@raspberryyocto:~# vi /mnt/fat/config.txt

and add:

dtparam=i2c_arm=on

Restart to apply your changes.
After the system has booted into Linux again we will first check if the i2c_bcm2708 module has been loaded:

root@yoctopi:~# lsmod
Module                  Size  Used by
ipv6                  350447  28
i2c_dev                 6115  2
evdev                  11396  1
joydev                  8960  0
bcm2835_gpiomem         3036  0
i2c_bcm2708             4834  0
bcm2835_wdt             3225  0
rpi_ft5406              4612  0
uio_pdrv_genirq         3164  0
rpi_backlight           2064  0
uio                     8128  1 uio_pdrv_genirq

Now we must add the i2c device by doing:

root@yoctopi:~# touch /etc/modules
root@yoctopi:~# echo 'i2c-dev' >> /etc/modules

Reboot again. When all went good we can now use the ic2detect tool to see if the Pi is able to communicate with our temperature sensor:

root@yoctopi:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

With everything setup and good to go I can now start developing my application. Stay tuned for more!

Creating an IoT thermostat (part II)

Creating a Yocto based Linux distribution for my embedded thermostat

Intro

This write-up will focus on how to create your own Linux distribution, using Yocto. Yocto is a popular tools these days for creating an embedded operating system from scratch. I’m not going to talk you into how Yocto works, where it came from and so on. If you have no idea at all then go visit the Yocto Project website.

Because this is going to be a single unit creation you might think that it is a bit silly to go through the entire phase of creating you own Linux distribution. Well, off course that’s true, using a full blown distribution like Debian, Fedora or Ubuntu might have the benefits of having the distribution already created for you, with every tool available that you’ll ever need. Creating a Yocto based distribution also has some benefits of its own. For example you can add or remove system components and use only those you really need. This may for example reduce boot time. Furthermore, you have more control over your system, you can toss in/out the components that you require and so the OS isn’t bloated either with programs and tools that you’d never use. This may gratefully reduce the OS’s footprint. And actually it’s a good training to get to know the Yocto Project because it is often used nowadays in embedded systems. At least if that’s where you’re interested in.

The embedded device I’m about to use is the Raspberry Pi 2. The reason I’m choosing this device is simple: it has all the components that I need, it has support for many add-ons, it has a large community which may help you out whenever you get into trouble, it’s relatively cheap to buy and easy to find in stores, and I have already sitting one on my desk waiting for an application to be used in.

Pi2ModB1GB_-comp

(Bit)baking your own  Linux distribution

I could go through all the steps of how to create a Yocto based distribution for your Raspberry Pi. Fact is that someone already did write a very good tutorial which I’ve couldn’t done better, so first head over to the Jumpnowtek website and follow the tutorial. Furthermore this guy already did a lot of work for you so his using his layer for raspberry pi will add support for many devices. You can find his Git repo here. For those who’re not fund on compiling their own Yocto distribution but instead just want to go ahead and use it, you can also find downloadable content on the Jumpnowtek download sector.

For my Yocto project I’ve used my Dell XPS 15 laptop with a second HDD of 512Gb installed, 8Gb of RAM and the Ubuntu 16.04 LTS operating system. Because I had this drive already available I’m using this one, but if you’re about to buy a new build setup look for something which is fast, which has a CPU with many cores, which contains a lot of DRAM, and something that uses a SDD. Using faster build systems might dramatically reduce build times because building your own distribution on a system of few years old might easily take 6 to 8 hours!

I creating a dedicated directory (/media/geoffrey/Data/yocto-pi) on my second hard drive and I’ll use this directory to make all of my yocto builds. First pull-in all required repos as instructed on the Jumpnowtek website and initialize your build directory. Because I’m going to be using the Qt5 framework (a C++ UI framework) I’ll be building a QT5 Yocto image and so I need to include several QT5 layers. Here is my bblayers.conf file:

# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

BBLAYERS ?= " \
    /media/geoffrey/Data/yocto-pi/poky-morty/meta \
    /media/geoffrey/Data/yocto-pi/poky-morty/meta-poky \
    /media/geoffrey/Data/yocto-pi/poky-morty/meta-openembedded/meta-oe \
    /media/geoffrey/Data/yocto-pi/poky-morty/meta-openembedded/meta-multimedia \
    /media/geoffrey/Data/yocto-pi/poky-morty/meta-openembedded/meta-networking \
    /media/geoffrey/Data/yocto-pi/poky-morty/meta-openembedded/meta-python \
    /media/geoffrey/Data/yocto-pi/poky-morty/meta-qt5 \
    /media/geoffrey/Data/yocto-pi/poky-morty/meta-raspberrypi \
    /media/geoffrey/Data/yocto-pi/rpi/meta-rpi \
  "

And here is my local.conf:

# Local configuration for meta-rpi images
# Yocto Project 2.2 Poky distribution [morty] branch
# This is a sysvinit system

LICENSE_FLAGS_WHITELIST = "commercial"

DISTRO_FEATURES = "ext2 pam opengl usbhost ${DISTRO_FEATURES_LIBC}"

DISTRO_FEATURES_BACKFILL_CONSIDERED += "pulseaudio"

PREFERRED_PROVIDER_jpeg = "libjpeg-turbo"
PREFERRED_PROVIDER_jpeg-native = "libjpeg-turbo-native"

PREFERRED_PROVIDER_udev = "eudev"
VIRTUAL_RUNTIME_init_manager = "sysvinit"

MACHINE_FEATURES_remove = "apm"

IMAGE_FSTYPES = "tar.xz ext3"

PREFERRED_VERSION_linux-raspberrypi = "4.4.%"

MACHINE = "raspberrypi"

#DL_DIR = "/media/geoffrey/Data/yocto-pi/rpi/build/sources"

#SSTATE_DIR = "/media/geoffrey/Data/yocto-pi/rpi/build/sstate-cache"

#TMPDIR = "/media/geoffrey/Data/yocto-pi/rpi/build/tmp"

DISTRO = "poky"

PACKAGE_CLASSES = "package_ipk"

DISABLE_OVERSCAN = "1"
DISPMANX_OFFLINE = "1"
ENABLE_UART = "1"
ENABLE_RPI3_SERIAL_CONSOLE = "1"

# i686 or x86_64
SDKMACHINE = "x86_64"

EXTRA_IMAGE_FEATURES = "debug-tweaks"

USER_CLASSES = "image-mklibs image-prelink"

PATCHRESOLVE = "noop"

RM_OLD_IMAGE = "1"

CONF_VERSION = "1"

I’ve build the Yocto image using following command:

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi$ source poky-morty/oe-init-build-env /media/geoffrey/Data/yocto-pi/rpi/build

## Shell environment set up for builds. ###

You can now run 'bitbake '

Common targets are:
 core-image-minimal
 core-image-sato
 meta-toolchain
 meta-toolchain-sdk
 adt-installer
 meta-ide-support

You can also run generated qemu images with a command like 'runqemu qemux86'

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$ bitbake qt5-basic-image

Wait for the build to complete and next copy your files to the SD card using the Jumpnowtek site’s instructions. Make sure you copy it to the correct disk!

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 465,8G 0 disk
├─sda1 8:1 0 244,8G 0 part /
├─sda2 8:2 0 220,6G 0 part
└─sda3 8:3 0 450M 0 part
sdc 8:32 1 3,7G 0 disk
├─sdc1 8:33 1 64M 0 part
└─sdc2 8:34 1 3,6G 0 part 

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ sudo mkdir /media/card
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ sudo ./mk2parts.sh sdc
[sudo] wachtwoord voor geoffrey: 

Working on /dev/sdc

umount: /dev/sdc: not mounted
DISK SIZE – 3963617280 bytes 

Okay, here we go ... 

=== Zeroing the MBR === 

1024+0 records gelezen
1024+0 records geschreven
1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,53551 s, 2,0 MB/s 

=== Creating 2 partitions === 

Checking that no-one is using this disk right now ... OK 

Disk /dev/sdc: 3,7 GiB, 3963617280 bytes, 7741440 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes 

>>> Created a new DOS disklabel with disk identifier 0x6efbfa0c.
Created a new partition 1 of type 'W95 FAT32 (LBA)' and of size 64 MiB.
/dev/sdc2: Created a new partition 2 of type 'Linux' and of size 3,6 GiB.
/dev/sdc3:
New situation:

Apparaat Op. Start Einde Sectoren Size Id Type
/dev/sdc1 * 8192 139263 131072 64M c W95 FAT32 (LBA)
/dev/sdc2 139264 7741439 7602176 3,6G 83 Linux

The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

=== Done! ===

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 465,8G 0 disk
├─sda1 8:1 0 244,8G 0 part /
├─sda2 8:2 0 220,6G 0 part
└─sda3 8:3 0 450M 0 part
sdc 8:32 1 3,7G 0 disk
├─sdc1 8:33 1 64M 0 part
└─sdc2 8:34 1 3,6G 0 part
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ export OETMP=/media/geoffrey/Data/yocto-pi/rpi/build/tmp
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ export MACHINE=raspberrypi
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ ./copy_boot.sh sdc
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/meta-rpi/scripts$ ./copy_rootfs.sh sdc qt5 raspberryyocto

OETMP: /media/geoffrey/Data/yocto-pi/rpi/build/tmp
IMAGE: qt5
HOSTNAME: raspberryyocto

Formatting /dev/sdc2 as ext4
[sudo] wachtwoord voor geoffrey:
/dev/sdc2 bevat een ext4-bestandssysteem met label 'ROOT'
 laatst aangekoppeld op /media/card op Wed Mar 29 11:33:06 2017
Toch doorgaan? (j,n) j
Mounting /dev/sdc2
Extracting qt5-image-raspberrypi.tar.xz to /media/card
Writing raspberryyocto /etc/hostname
Unmounting /dev/sdc2
Done

Creating a cross-platform toolchain for application development

Even though our embedded device might contain all the tools needed to compile native applications, most of the time you’ll be wanting to use the processing power of your development machine to speed up development. For this reason we need to install the cross-compilation toolchain. But first we need to create the toolchain using bitbake. Navigate to your working directory and use following command to build the toolchain:

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi$ source poky-morty/oe-init-build-env /media/geoffrey/Data/yocto-pi/rpi/build

### Shell environment set up for builds. ###

You can now run 'bitbake '

Common targets are:
 core-image-minimal
 core-image-sato
 meta-toolchain
 meta-ide-support

You can also run generated qemu images with a command like 'runqemu qemux86'
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$ clear; bitbake meta-toolchain-qt5
Loading cache: 100% |##################################################################| Time: 0:00:00
Loaded 2660 entries from dependency cache.
Parsing recipes: 100% |################################################################| Time: 0:00:01
Parsing of 1972 .bb files complete (1964 cached, 8 parsed). 2668 targets, 353 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION = "1.32.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "arm-poky-linux-gnueabi"
MACHINE = "raspberrypi"
DISTRO = "poky"
DISTRO_VERSION = "2.2.1"
TUNE_FEATURES = "arm armv6 vfp arm1176jzfs callconvention-hard"
TARGET_FPU = "hard"
meta
meta-poky = "morty:a3fa5ce87619e81d7acfa43340dd18d8f2b2d7dc"
meta-oe
meta-multimedia
meta-networking
meta-python = "morty:1efa5d623bc64659b57389e50be2568b1355d5f7"
meta-qt5 = "morty:9aa870eecf6dc7a87678393bd55b97e21033ab48"
meta-raspberrypi = "master:e1f69daa805cb02ddd123ae2d4d48035cb5b41d0"
meta-rpi = "morty:03841471ccaed549a2a14a896c13f71af76cf482"

Initialising tasks: 100% |#############################################################| Time: 0:00:05
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 3170 tasks of which 1605 didn't need to be rerun and all succeeded.
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build$

Again, this will take a lot of time, depending on how fast your dev-pc is. When the build completes you’ll get as a result the script that install the SDK  on your development pc. On my pc it was found in the /media/geoffrey/Data/yocto-pi/rpi/build/tmp/deploy/sdk folder. The script is named poky-glibc-x86_64-meta-toolchain-qt5-arm1176jzfshf-vfp-toolchain-2.2.1.sh.

Run the script, and when asked for the install folder I’ve chosen the default option. If you plan to create more than one SDK I’d highly recommend to install each in their own directory. There is no need to run this script as root user. Note that running this script takes roughly 2 minutes to complete, enough time to grab a dieet coke!

geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build/tmp/deploy/sdk$ ./poky-glibc-x86_64-meta-toolchain-qt5-arm1176jzfshf-vfp-toolchain-2.2.
1.sh
Poky (Yocto Project Reference Distro) SDK installer version 2.2.1
=================================================================
Enter target directory for SDK (default: /opt/poky/2.2.1):
You are about to install the SDK to "/opt/poky/2.2.1". Proceed[Y/n]? Y
[sudo] password for geoffrey:
Extracting SDK............................................................................................................................done
Setting it up...done
SDK has been successfully set up and is ready to be used.
Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.
 $ . /opt/poky/2.2.1/environment-setup-arm1176jzfshf-vfp-poky-linux-gnueabi
geoffrey@geoffrey-Dell-XPS-L502X:/media/geoffrey/Data/yocto-pi/rpi/build/tmp/deploy/sdk$

Compiling your first program

We came as far as creating a self-made Yocto based distribution with Qt5.7 pre-installed, plus having all the tools installed on our development pc to create a nice embedded application. If you don’t use an IDE then go ahead and use the instructions on the Jumpnowtek website to go ahead and compile your application using qmake.

geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ source /opt/poky/2.2.1/environment-setup-arm1176jzfshf-vfp-poky-linux-gnueabi
geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ qmake && make -j4
sh: OE_QMAKE_CXX: opdracht niet gevonden
sh: OE_QMAKE_CXXFLAGS: opdracht niet gevonden
Info: creating stash file /home/geoffrey/Qt5.5.1/Projects/HelloQtWidgets/.qmake.stash
/opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/qt5/uic mainwindow.ui -o ui_mainwindow.h
arm-poky-linux-gnueabi-g++ -march=armv6 -mfpu=vfp -mfloat-abi=hard -mtune=arm1176jzf-s -mfpu=vfp --sysroot=/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi -c -pipe -O2 -pipe -g -feliminate-unused-debug-types -std=c++11 -O2 -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5 -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtGui -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtCore -I. -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/lib/qt5/mkspecs/linux-oe-g++ -o main.o main.cpp
arm-poky-linux-gnueabi-g++ -march=armv6 -mfpu=vfp -mfloat-abi=hard -mtune=arm1176jzf-s -mfpu=vfp --sysroot=/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi -c -pipe -O2 -pipe -g -feliminate-unused-debug-types -std=c++11 -O2 -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5 -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtGui -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtCore -I. -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/lib/qt5/mkspecs/linux-oe-g++ -o qsimpledigitalclock.o qsimpledigitalclock.cpp
/opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/qt5/moc -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/lib/qt5/mkspecs/linux-oe-g++ -I/home/geoffrey/Qt5.5.1/Projects/HelloQtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5 -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtGui -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtCore -I/usr/include -I/usr/local/include mainwindow.h -o moc_mainwindow.cpp
/opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/qt5/moc -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/lib/qt5/mkspecs/linux-oe-g++ -I/home/geoffrey/Qt5.5.1/Projects/HelloQtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5 -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtGui -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtCore -I/usr/include -I/usr/local/include qsimpledigitalclock.h -o moc_qsimpledigitalclock.cpp
arm-poky-linux-gnueabi-g++ -march=armv6 -mfpu=vfp -mfloat-abi=hard -mtune=arm1176jzf-s -mfpu=vfp --sysroot=/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi -c -pipe -O2 -pipe -g -feliminate-unused-debug-types -std=c++11 -O2 -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5 -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtGui -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtCore -I. -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/lib/qt5/mkspecs/linux-oe-g++ -o mainwindow.o mainwindow.cpp
arm-poky-linux-gnueabi-g++ -march=armv6 -mfpu=vfp -mfloat-abi=hard -mtune=arm1176jzf-s -mfpu=vfp --sysroot=/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi -c -pipe -O2 -pipe -g -feliminate-unused-debug-types -std=c++11 -O2 -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5 -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtGui -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtCore -I. -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/lib/qt5/mkspecs/linux-oe-g++ -o moc_mainwindow.o moc_mainwindow.cpp
arm-poky-linux-gnueabi-g++ -march=armv6 -mfpu=vfp -mfloat-abi=hard -mtune=arm1176jzf-s -mfpu=vfp --sysroot=/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi -c -pipe -O2 -pipe -g -feliminate-unused-debug-types -std=c++11 -O2 -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5 -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtWidgets -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtGui -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/include/qt5/QtCore -I. -I. -I/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/lib/qt5/mkspecs/linux-oe-g++ -o moc_qsimpledigitalclock.o moc_qsimpledigitalclock.cpp
arm-poky-linux-gnueabi-g++ -march=armv6 -mfpu=vfp -mfloat-abi=hard -mtune=arm1176jzf-s -mfpu=vfp --sysroot=/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-O1 -o HelloQtWidgets main.o mainwindow.o qsimpledigitalclock.o moc_mainwindow.o moc_qsimpledigitalclock.o -L/opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi/usr/lib -lQt5Widgets -lQt5Gui -lQt5Core -lGLESv2 -lpthread
geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$

If you’d get the error:

qmake: could not exec '/usr/lib/x86_64-linux-gnu/qt4/bin/qmake': No such file or directory

… you probable forget to use the source command! Note that the source command is bound to the shell where you used it. If you used it inside a shell script than it will only take effect to the commands inside the shell script!

After compiling has completed you get several files as output. One of the files is the binary executable that represent our program. We can also verify if is has been compiled for ARM:

geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ ls -l HelloQtWidgets
-rwxrwxr-x 1 geoffrey geoffrey 1181132 feb 18 17:33 HelloQtWidgets
geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ ^C
geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ file HelloQtWidgets
HelloQtWidgets: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=56d390438db87a396f5f28e7adbbdd69cdd0ee68, not stripped

We can now copy the file over to our embedded system:

geoffrey@geoffrey-Dell-XPS-L502X:~/Qt5.5.1/Projects/HelloQtWidgets$ scp HelloQtWidgets root@192.168.0.205:/home/root
HelloQtWidgets 100% 1153KB 1.1MB/s 00:00

Next, login to the embedded system using ssh and execute the binary file. You’ll need to have a display attached to your pi in order to view the UI:

geoffrey@geoffrey-Dell-XPS-L502X:~$ ssh root@192.168.0.205
root@raspberryyocto:~# ls
HelloQtWidgets
root@raspberryyocto:~# ./HelloQtWidgets
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).

Setting up QtCreator

Whenever you’re about to create a more advanced program with an UI you’ll find yourselve in the need of a IDE. QtCreator is quit good in providing all the tools you need to create graphical applications so I highly recommend using QtCreator to develop your applications. We’ll now configure QtCreator to use the SDK we’ve used above.

First you need to install QtCreator. Go to the Qt website, fill in the licence form and download Qt5.7. You may also look for the open source version of Qt here. Next make the downloaded file executable and run it. You may install Qt in the default folder. Next we’ll configure QtCreator to use the compiler, debugger, etc. Note that for compiling native applications for our embedded system we need to source the SDK folder each time we run QtCreator. For convenience I created a script that does this for me:

geoffrey@geoffrey-Dell-XPS-L502X:~$ vim qtcreator4pi.sh

Enter following content:

#!/bin/bash
source /opt/poky/2.2.1/environment-setup-arm1176jzfshf-vfp-poky-linux-gnueabi
/home/geoffrey/Qt5.7.0/Tools/QtCreator/bin/qtcreator&

Save the script, make it executable and run it:

geoffrey@geoffrey-Dell-XPS-L502X:~$ chmod +x qtcreator4pi.sh
geoffrey@geoffrey-Dell-XPS-L502X:~$ ./qtcreator4pi.sh

schermafdruk-van-2017-02-18-15-14-49

You should now see the default welcome page for QtCreator. Next from the main menu bar at the top of the application click the Tools menu item and open the Options window. Now do following steps (note that some steps might look a bit different as the screenshots I’ve made are made on a Qt5.5 setup):

Create your device

Navigate to Devices, click Add, select Generic Linux Device and start the Wizard. Enter following content:
Name: [pick your own name, for example Pi One]
Hostname: [the IP address of your raspberry pi]
Username: root
Authentication type: Password
Password: [leave empty]

Click next, QtCreator will now test your connection and if all goes well you’d get following output:

Connecting to host...

Checking kernel version...

Linux 4.4.43 armv6l

Checking if specified ports are available...

All specified ports are available.

Device test finished successfully.

schermafdruk-van-2017-02-18-12-12-56

Make sure to Apply your configuration at this point.

Configure the Qt Version

Navigate to Build &Run > Qt Versions, click Add. If not already selected, navigate and select the /opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/qt5/qmake executable. Adjust the path to your needs.

schermafdruk-van-2017-02-18-12-24-46

Configure the compiler

Navigate to Build & Run > Compilers, click Add, select GCC and use following settings:
Name: [choose your own name, for example Pi One GCC]
Compiler Path: /opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-g++

schermafdruk-van-2017-02-18-12-46-26

Configure the debugger

Navigate to Build & Run > Debuggers, click Add and use following settings:
Name: [choose your own name, for example Pi One GDB]
Path: /opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gdb

schermafdruk-van-2017-02-18-12-50-00

Configure the kit (aka hook everything up together)

Navigate to Build & Run > Kits, click Add, and enter following content.
Name: [choose your own name, for example Pi One]
Device Type: Generic Linux Device
Device: [choose the device we created earlier]
Sysroot: /opt/poky/2.2.1/sysroots/arm1176jzfshf-vfp-poky-linux-gnueabi
Compiler: [choose the compiler we configured earlier]
Debugger: [choose the debugger we configured earlier]
Qt Version: [choose the Qt version we configured earlier]
Qt mkspec: linux-oe-g++

schermafdruk-van-2017-02-18-17-59-50

We’ve now correctly configured QtCreator for cross-platform development. We need to perform this configuration only once per SDK. Note that whenever you’re going to compile, deploy or debug your application on your embedded device that you launch QtCreator using the script we created earlier (the one that contains the source command). If however your target machine is your own pc you don’t need to source in any SDK and so you can launch QtCreator directly from command line or or using any desktop shortcut.

Building & running applications

With QtCreator configured to use our embedded device’s SDK we can now open a demo application. Note, because I’ve chosen the qt5-basic-image we must take note that not all Qt5 libraries will be available on our target machine. So while QtCreator does provide quite some Qt demo apps, some may work for you.

For this purpose I’ll use a self made demo app. Make sure you’ve launched QtCreator with using our launch script, and open the demo application project. The project might not yet contain build settings that allows us to choose the Pi One kit as build target. We can add this by selecting the Projects button on the left menu bar, click Add kit and select the one we’ve configured earlier. In my case I’d select Pi One:

schermafdruk-van-2017-02-18-14-04-49

Now, from the left menu bar select your target kit:

schermafdruk-van-2017-02-18-14-04-49

Use the hammer icon the build your application. As a result you’ll find a new directory inside your QtCreator working directory, and inside you’ll find the executable binary file we just created.

By now we have our own Linux based OS with all the tools installed to develop our thermostat UI an backend software. Stay tuned for more.

Creating an IoT thermostat (part I)

In the following few series of blog posts I’m about to explain how I made myself an internet connected (or IoT, if you will) thermostat.

What I own now (and will soon become obsolete)

Currently I’m controlling my house’s heating system with a Theben RAM 325:

ram-325

My first goal was to get a some understanding of how the current thermostat was doing its job. I don’t own the manual anymore so I was more or less on my own to figure out how to use this thermostat. Well, it’s not overly complicated, and in the end I found at that the Theben RAM725 works as a replacement for the RAM325 so I could go use the 725’s manual as reference.

The left side if the thermostat houses a 12h clock. In the upper left corner we find an indicator which tells us tells us weather it’s in “normal” (day) or “energy saving” (night) mode. The picture above is taken with the energy mode in “normal”. On the bottom right side we can find the temperature setting which allows us to set the energy saving mode temperature. A more advanced version also has a second temperature settings used to set the temperature during normal operation. At the top right we find the program selection switch which has 3 pre-defined programs: automatic program (clock icon), forced energy saving program (moon icon), and the comfort program (the one that is currently selected) where the thermostatic taps decide the temperature.

What you don’t see in this picture is that behind the clock we can set “on” and “off” jumpers which are used in automatic mode. There is also a LED located at the front which indicates when the heating system is heating.

img_20170128_140112

The back side tells us its 230V powered (connectors 4 and 5). Connectors 1, 2, and 3 are used to control the heater (gas burner, valve, …). Here are some wiring examples:

There is also a small adjustment screw on the upper left side which allows tweaking the temperature trigger point.

Although this thermostat does a good job in what it needs to do, it’s pretty cheap and reliable, but it’s not really the most sexy thing to have in house and for an embedded engineer that I am a perfect goal to tackle on my own!

The newcomer

The embedded device I’m about to use is the Raspberry Pi 2. The reason I’m choosing this device is simple: it has all the components that I need, it has support for many add-ons, it has a large community which may help you out whenever you get into trouble, it’s relatively cheap to buy and easy to find in stores, and I have already sitting one on my desk waiting for an application to be used in. Furthermore it has a pretty decent touch screen and all sorts housing available so that I don’t have to tech the entire system by myself.

With that given this will be the first article in series of 3 to 4 articles in which I’ll tell you how I came to build my own modern thermostat. Stay tuned for more!

Logging temperature using an Arduino and AD7410 sensor

This article is a quick and dirty demonstration to hack yourself a temperature data logger which saves its results to an SD card. The sensor of use is a HTU21D, a I²C temperature and humidity sensor.

hookup

Schematic:

hookup_bb

I hooked up a HTU21D sensor to an Arduino Uno + SD-card shield and let it monitor temperature (and humidity) over an entire day:

24h_log

Here is a close-up of what happens at night:

3h_log

Source code:

/*
 SD card datalogger

This example shows how to log data from three analog sensors
 to an SD card using the SD library.

The circuit:
 * analog sensors on analog ins 0, 1, and 2
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4

created 24 Nov 2010
 modified 9 Apr 2012
 by Tom Igoe

This example code is in the public domain.

*/
 /*
 HTU21D Humidity Sensor Example Code
 By: Nathan Seidle
 SparkFun Electronics
 Date: September 15th, 2013
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 Uses the HTU21D library to display the current humidity and temperature

 Open serial monitor at 9600 baud to see readings. Errors 998 if not sensor is detected. Error 999 if CRC is bad.

 Hardware Connections (Breakoutboard to Arduino):
 -VCC = 3.3V
 -GND = GND
 -SDA = A4 (use inline 330 ohm resistor if your board is 5V)
 -SCL = A5 (use inline 330 ohm resistor if your board is 5V)

*/

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "SparkFunHTU21D.h"

//Create an instance of the object
HTU21D myHumidity;

const int chipSelect = 4;

// make a string for assembling the data to log:
String dataString = "";

void setup() {
 // Open serial communications and wait for port to open:
 Serial.begin(9600);
 while (!Serial) {
 ; // wait for serial port to connect. Needed for native USB port only
 }

 myHumidity.begin();
 Serial.println("HTU21D ready!");

Serial.print("Initializing SD card...");

// see if the card is present and can be initialized:
 if (!SD.begin(chipSelect)) {
 Serial.println("Card failed, or not present");
 // don't do anything more:
 return;
 }
 Serial.println("card initialized.");
}

void loop() {
 readTemp();

Serial.println("Writing data...");
 // open the file. note that only one file can be open at a time,
 // so you have to close this one before opening another.
 File dataFile = SD.open("datalog.txt", FILE_WRITE);

// if the file is available, write to it:
 if (dataFile) {
 dataFile.println(dataString);
 dataFile.close();
 // print to the serial port too:
 Serial.println(dataString);
 }
 // if the file isn't open, pop up an error:
 else {
 Serial.println("error opening datalog.txt");
 }
 delay(10000);
}

void readTemp() {
 float humd = myHumidity.readHumidity();
 float temp = myHumidity.readTemperature();

 // make a string for assembling the data to log:
 dataString = "Time: ";
 dataString += String(millis());
 dataString += String("; Temperature: ");
 dataString += String(temp);
 dataString += String("; Humidity: ");
 dataString += String(humd);
 dataString += String("%");
}

This was just a quick and dirty hack to get some instant results. I’m planing to do some more logging in the future to get a better understanding of how to approach my self build climate control. Stay tuned for more.

Arduino and AD7410 I²C temp sensor

On request, the source code of using the Analog Devices AD7410 I²C temp sensor. (Datasheet: adt7410)

#include <Wire.h>

//ADT7410 13/16-bit digital temperature sensor
//RED (VDD): 2.7 ... 5.5V
//BROWN (GND): 0V
//Arduino uno, wires:
//PURPLE 1 (SCL): SCL (near AREF, should be equal to ANALOG5)
//PURPLE 2 (SDA): SDA (near AREF, should be equal to ANALOG4)
//Arduino due, wires:
//PURPLE 1 (SCL): SCL (pin 21)
//PURPLE 2 (SDA): SDA = (pin 20)
//Arduino IDE 1.5 compatible

#define ADT7410_I2C_ADDRESS 0x48
#define tempRegister 0x00
#define configRegister 0x03
#define selectCode16bitMode 0x80


void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600); // serial connection
  set16bitMode();
}




void loop() {
  delay(5000);
  serieelPrint(); //print on serial port
}


//set ADT7410 in 16-bit temp value mode
void set16bitMode() 
{
  Serial.println("Setting 16-bit mode...");
  Wire.beginTransmission(ADT7410_I2C_ADDRESS);
  Wire.write(configRegister);
  Wire.write(selectCode16bitMode);
}



//gives back the temperature value
float readTemp()
{
  //set read register
  Wire.beginTransmission(ADT7410_I2C_ADDRESS);
  Wire.write(tempRegister);
  Wire.endTransmission();
  //receive data
  Wire.requestFrom(ADT7410_I2C_ADDRESS, 2);
  byte MSB = Wire.read();
  byte LSB = Wire.read();
  
  //check for positive or negative sign
  boolean sign;
  if(MSB>0xA0) {
    sign=0; //negative
  } else {
    sign=1; //positive
  }
  
  //concat MSB&LSB
  float tempValue = MSB * 256;
  tempValue+=LSB;
  
  //BIN to DEC
  if(!(sign)){
    tempValue-=65536;
  }
  tempValue/=128;
  
  return tempValue;
}

void serieelPrint()
{
  Serial.print("Unit: ");
  Serial.print(ADT7410_I2C_ADDRESS, HEX);
  Serial.print(" *** temperature: ");
  //temperature readout
  Serial.print(readTemp());
  Serial.println(" degrees Celcius");
}

UPDATE: you can find my Arduino library here: https://github.com/geoffrey-vl/Easy_ADT7410_Arduino_Library

Samsung Galaxy S3 Mini CyanogenMod 12.1 (Android 5.1)

Sporting Android 4.1 and dual ARM Cortex A9 cpu’s the Samsung Galaxy S3 Mini (GT-I8190) is no longer competitive with any mid-range smartphones currently found in stores (read more). However, because of its wide community the smartphone has become a interesting target for creating custom ROM’s. In this guide I’ll go through some commands which will help you upgrading the S3 mini from stock Android 4.1 to Android Lollipop 5.1!

Notice that for performing this modification I’ll be using and SD-card and my laptop with Ubuntu 16.4 operating system installed. Before we get along make sure to visit the NovaFusion.pl website, head over to the download page and download following files:

If the site offers you the choice between Recovery and Oden take the Recovery option. It means we’re going to perform the flash through the recovery menu which is build inside the device. The Odin option is used for flashing the ROM through the Odin utility for Samsung smartphones. Caynogenmod 12.1 is the custom ROM we’re going to install and features Android Lollipop 5.1. TWRP Recovery is an enhanced software tool which is more feature rich than the S3 Mini’s default recovery tool. We need it to flash to custom ROM. Also head over to the opengapps.org website and download the latest Google Apps application suite compiled for your platform. To be sure you have the correct version select following checkboxes before hitting the download button: “ARM Platform”, “Android 5.1”, “stock variant”. This stock variant of Google Apps (often referred to as Gapps) includes a whole list of Google applications: Play Store, Chrome browser, Calculator, Drive, Docs, Keep, Fitness, Keyboard, Maps, YouTube, … See the complete list here. You can also use following link which will take you directly start downloading Gapps for you Samsung S3 Mini: Gapps for Samsung S3 Mini.

Now grab your SD-card, head over to your computers download folder and copy the Gapps and Cyanogenmod zipfiles onto your SD-card. After copying has been completed install the SD-card into your S3 Mini. Next we’re going to boot or reboot the smartphone into “download” mode (sometimes also referred to as “Odin” mode). You can this by holding Power + Volume Down + Menu buttons at the same time when powering up your smartphone. You can also reboot into download mode when your phone is on by installing Google’s ADB debug tool (sudo apt-get install android-tools-adb android-tools-fastboot) and issuing following command: adb reboot download. Note that must have USB debugging enabled and you must be connected to your device.

All-Galaxy-S3-Download-Mode-580x362

booting Samsung Galaxy S3 Mini into “download/Odin” mode

The download mode is specific to Samsung smartphones, but it is similar to the Fastboot mode found on many different smartphones with unlocked bootloader.

Next we’ll use the Heimdall tool to flash the TWRP recovery tool into our smartphone’s memory. On Ubuntu you can install it by issuing following command: sudo apt-get install heimdall. On your computer head over to you download folder and unzip the twrp’s zipfile. Inside the unzipped folder you’ll find a “recovery.img” image file which we’ll flash. Open a command terminal from this location and issue following command:

sudo heimdall flash –Kernel2 recovery.img –no-reboot

We’ll get following outcome:

Heimdall v1.4.0

Copyright (c) 2010-2013, Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/

This software is provided free of charge. Copying and redistribution is
encouraged.

If you appreciate this software and you would like to support future
development please consider donating:
http://www.glassechidna.com.au/donate/

Initialising connection...
Detecting device...
Claiming interface...
Setting up interface...

Initialising protocol...
Protocol initialisation successful.

Beginning session...

Some devices may take up to 2 minutes to respond.
Please be patient!

Session begun.

Downloading device's PIT file...
PIT file download successful.

Uploading Kernel2
100%
Kernel2 upload successful

Ending session...
Releasing device interface...

This command flashes the TWRP’s binary image “recovery.img” into the “Kernel2” recovery partition. On your smartphone a blue bar will appear that will show the progress. If for some reason this “Kernel2” partition is not available on your S3 Mini you can discover the target partition by yourself by issuing following command:

sudo heimdall print-pit –verbose

It will result in following outcome (the target partition is marked in blue and can be found because it is the partition holding the recovery.img Flash filename):

Heimdall v1.4.0

Copyright (c) 2010-2013, Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/

This software is provided free of charge. Copying and redistribution is
encouraged.

If you appreciate this software and you would like to support future
development please consider donating:
http://www.glassechidna.com.au/donate/

Initialising connection...
Detecting device...
 Manufacturer: "SAMSUNG"
 Product: "SAMSUNG USB DRIVER"
 Serial No: " "

length: 18
 device class: 2
 S/N: 3
 VID:PID: 04E8:685D
 bcdDevice: 0100
 iMan:iProd:iSer: 1:2:3
 nb confs: 1

interface[0].altsetting[0]: num endpoints = 1
 Class.SubClass.Protocol: 02.02.01
 endpoint[0].address: 83
 max packet size: 0010
 polling interval: 09

interface[1].altsetting[0]: num endpoints = 2
 Class.SubClass.Protocol: 0A.00.00
 endpoint[0].address: 81
 max packet size: 0200
 polling interval: 00
 endpoint[1].address: 02
 max packet size: 0200
 polling interval: 00
Claiming interface...
Setting up interface...

Initialising protocol...
Protocol initialisation successful.

Beginning session...

Some devices may take up to 2 minutes to respond.
Please be patient!

Session begun.

Downloading device's PIT file...
PIT file download successful.

Entry Count: 25
Unknown 1: 1598902083
Unknown 2: 844251476
Unknown 3: 28519
Unknown 4: 25708
Unknown 5: 28261
Unknown 6: 0
Unknown 7: 0
Unknown 8: 0


--- Entry #0 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 1
Attributes: 2 (STL Read-Only)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 0
Partition Block Count: 256
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: MBR,GPT
Flash Filename: 
FOTA Filename:


--- Entry #1 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 2
Attributes: 2 (STL Read-Only)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 256
Partition Block Count: 768
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: MasterTOC
Flash Filename: STE_boot.bin
FOTA Filename:


--- Entry #2 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 70
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 1024
Partition Block Count: 2048
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: PIT
Flash Filename: goldenxx.pit
FOTA Filename:


--- Entry #3 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 71
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 6144
Partition Block Count: 2048
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: MD5HDR
Flash Filename: md5.img
FOTA Filename:


--- Entry #4 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 3
Attributes: 2 (STL Read-Only)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 8192
Partition Block Count: 1024
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: STEboot1
Flash Filename: STE_boot1.img
FOTA Filename:


--- Entry #5 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 4
Attributes: 2 (STL Read-Only)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 9216
Partition Block Count: 1024
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: STEboot2
Flash Filename: STE_boot2.img
FOTA Filename:


--- Entry #6 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 5
Attributes: 2 (STL Read-Only)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 10240
Partition Block Count: 1024
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: Dnt
Flash Filename: dnt.ssw
FOTA Filename:


--- Entry #7 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 6
Attributes: 2 (STL Read-Only)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 11264
Partition Block Count: 1024
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: reserved
Flash Filename: 
FOTA Filename:


--- Entry #8 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 7
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 16384
Partition Block Count: 2048
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: CSPSAFS
Flash Filename: cspsa.img
FOTA Filename:


--- Entry #9 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 8
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 18432
Partition Block Count: 2048
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: CSPSAFS2
Flash Filename: cspsa2.img
FOTA Filename:


--- Entry #10 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 9
Attributes: 5 (Read/Write)
Update Attributes: 5 (FOTA)
Partition Block Size/Offset: 20480
Partition Block Count: 32768
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: EFS
Flash Filename: EFS.img
FOTA Filename:


--- Entry #11 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 10
Attributes: 5 (Read/Write)
Update Attributes: 5 (FOTA)
Partition Block Size/Offset: 53248
Partition Block Count: 32768
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: ModemFS
Flash Filename: modemfs.img
FOTA Filename:


--- Entry #12 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 11
Attributes: 5 (Read/Write)
Update Attributes: 5 (FOTA)
Partition Block Size/Offset: 86016
Partition Block Count: 32768
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: ModemFS2
Flash Filename: modemfs2.img
FOTA Filename:


--- Entry #13 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 12
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 118784
Partition Block Count: 102400
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: Fota
Flash Filename: ssgtest.img
FOTA Filename:


--- Entry #14 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 13
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 380928
Partition Block Count: 128
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: IPL Modem
Flash Filename: ipl.bin
FOTA Filename:


--- Entry #15 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 14
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 385024
Partition Block Count: 28672
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: Modem
Flash Filename: modem.bin
FOTA Filename:


--- Entry #16 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 15
Attributes: 2 (STL Read-Only)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 417792
Partition Block Count: 4096
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: Loke4
Flash Filename: normal.bin
FOTA Filename:


--- Entry #17 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 16
Attributes: 2 (STL Read-Only)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 421888
Partition Block Count: 4096
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: 2ndLoke4
Flash Filename: normal2.bin
FOTA Filename:


--- Entry #18 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 17
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 425984
Partition Block Count: 32768
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: PARAM
Flash Filename: param.lfs
FOTA Filename:


--- Entry #19 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 18
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 458752
Partition Block Count: 32768
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: Kernel
Flash Filename: boot.img
FOTA Filename:


--- Entry #20 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 19
Attributes: 5 (Read/Write)
Update Attributes: 1 (FOTA)
Partition Block Size/Offset: 491520
Partition Block Count: 32768
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: Kernel2
Flash Filename: recovery.img
FOTA Filename:


--- Entry #21 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 20
Attributes: 5 (Read/Write)
Update Attributes: 5 (FOTA)
Partition Block Size/Offset: 524288
Partition Block Count: 2457600
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: SYSTEM
Flash Filename: system.img
FOTA Filename:


--- Entry #22 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 21
Attributes: 5 (Read/Write)
Update Attributes: 5 (FOTA)
Partition Block Size/Offset: 2981888
Partition Block Count: 1720320
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: CACHEFS
Flash Filename: cache.img
FOTA Filename:


--- Entry #23 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 22
Attributes: 5 (Read/Write)
Update Attributes: 5 (FOTA)
Partition Block Size/Offset: 4702208
Partition Block Count: 655360
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: HIDDEN
Flash Filename: hidden.img
FOTA Filename:


--- Entry #24 ---
Binary Type: 0 (AP)
Device Type: 2 (MMC)
Identifier: 23
Attributes: 5 (Read/Write)
Update Attributes: 5 (FOTA)
Partition Block Size/Offset: 5357568
Partition Block Count: 0
File Offset (Obsolete): 0
File Size (Obsolete): 0
Partition Name: DATAFS
Flash Filename: userdata.img
FOTA Filename: remained

Ending session...
Rebooting device...
Releasing device interface...

Sometimes you might bump into issues where the command line returns an error like “ERROR: Failed to receive handshake response. Result: -7“. To resolve this issue simply repeat the command or reboot your device into download mode once again.

When flashing has completed we should reboot the phone into recovery mode. You can do this by powering up your S3 Mini and holding the power + Volume Up + Menu buttons at the same time.

enter_recovery_mode_on_Galaxy_S3

booting Samsung Galaxy S3 Mini into “recovery” mode

Note that you should make sure to reboot into recovery directly after flashing TWRP. If for some reason your smartphone would have booted into normal mode again instead of recovery, the boot subsystem might have a protection system which restores the default recovery image into the recovery partition in place of our custom TWRP recovery image.

Once TWRP recovery is loaded you’ll be presented with following user interface:

1419274212077

TWRP recovery graphical interface

Before actually flashing Cyanogemod on your device it is best to make a backup. You can do this though the Backup button. Once this had completed you should perform a factory reset. This will wipe data, cache and dalvik cache. It can be done by using the Wipe button, next chose Factory Reset. To install Cyanogemod hit the Install button and select the cmXXX.zip file from you external storage device (SD-card). This process might take a while. Once this has completed redo the same process but this time install the gapps zip file that we also copied to the SD-card. Once installation has finished, return to the main menu and select Reboot, then System. The device will now boot into CyanogenMod 12.1 (Lollipop). The first boot into CM12 might take an addition large amount of time as some software still needs be installed automatically in the background. Before actually entering the Android main screen the Google’s setup wizard will also ask you for your google account and so on. Once you’ve completed the wizard the Android main menu will arise and you can go on using Android Lollipop on your Samsung Galaxy S3 Mini!

Screenshot_2015-03-25-18-04-36-338x600

CyanogenMod 12.1 for Samsung Galaxy S3 Mini