The BOV PAY MVP Problem

BOV has a problem – Revolut is seriously eating through its card payments business (and profits). Revolut in Malta is very famous and for a very good reason. No, it’s not because it provides free, VISA / Chip / Contactless cards; BOV does that as well. It’s because Revolut’s mobile app is just awesome. BOV seems to (finally) notice this and they have Revolut at their sights. How can BOV one-up Revolut? Tap-to-pay purchases!

BOV have been working on their now BOV PAY app – this will enable a mobile user to make purchases by tapping their phones. Mobile vendors have already developed this though; the likes of Google Pay, Apple Pay, Samsung Pay already exist. But here’s the problem – in Malta, only Apple Pay is officially supported, so non-android users are hung out to dry (unless you follow my unofficial guide here)

Smartly enough, BOV prioritized launching an app for Android firstly. The reason is simple – since there is no official tap-to-pay application in Malta, they’re tapping (pun intended) into an untapped market. So, android users, rejoice!..or should we?

You see, the application is in a very early phase; I’d say it’s just an MVP. The application is sluggish, the user experience is quite rubbish and the app is riddled with bugs. Tap-to-pay works, but the experience is frankly rubbish. Once I tapped my phone to pay, the app took more than 5 seconds to simply show the BOV screen and the card that I’ve paid with. But alas, it works.

Let’s discuss the next most infuriating thing. Honestly, once they get this (properly) working, I’ll seriously consider switching back to use BOV cards instead of Revolut cards daily. There is NO WAY to INSTANTLY see the transactions that I’ve affected!

Well, firstly, the new BOV PAY app does not show any transaction whatsoever. I’m guessing that this is a work in progress, and I should be using the older app to check the transaction. OK, fine. But, still, the old app does not enable me to INSTANTLY see my transaction. I’m able to see that there is a difference between book balance and available balance, but the transaction does not show up. This is PAINFUL – show me that I’ve made a payment, even though the payment may be reverted if unclaimed by merchant. It’s my right to see where my money went! UGH!

Anyway, let’s dive into some other criticism about the app; in no order:

  • It takes at least 5 seconds to get the BOV logo and the loading spinner
  • It takes another 5 seconds (or more) from successfully recognising my fingerprint into the main menu
  • I had to add all my personal details and sign up. Why did I had to provide my name, address and other information? Can’t this be derived from ownership of the card? Or maybe through the authentication of the classic BOV app?
  • When I press back, I prompted to log out; why? Isn’t it obvious that I’m the only person who’s using this app? Logout should be buried somewhere; I don’t need to see it every time.
  • The card controls feature is very weak – it only has ONE option. I’m guessing that this is WIP – no harm, no foul.
  • Again, I’m not sure why through the Review Card Details I’m able to edit information such as the expiry date, CVV, address. This needs to be done the other way round; I’d prove who I am and cards are added automagically for me and the relevant information is obtained from your records. This is a VERY WEIRD feature.
  • From a UI Experience. why does load the picture of the card each time? I’m always looking at a spinner before the card image is displayed.
  • Expiring sessions? Really? What’s protecting me from? As soon as the app is dismissed, THEN and only THEN the session should be terminated.
  • The locator feature; I’m assuming that this shows a list of ATMS? Poor naming?
  • The setting section looks very basic; but I guess it gets the job done. OK
  • The about us is very cheeky feature; it’s just a WebView of the BOV Site. Lazy!
  • Tutorials
    • The Pay-In-Site is a good and easy tutorial; the button to go to the cards section doesn’t work.
    • Using the App is again, a WebView of the BOV site.
    • Contact us – again, WebView.
  • Terms and Privacy – All WebViews (oh, did I mention that the site is NOT mobile friendly?)

I also must mention the fact that I’ve forwarded much of the feedback to BOV and they instantly got back to me over the phone to listen to my feedback. I must give credit where it’s due. I’m hoping that they the feedback that the clients are giving to them so that they can create an awesome app.

They’ve started on the right track, but they got so much progress to do. I’m just hoping that eventually they’ll introduce the Google Pay integration. But this will have to do for now. I’ll be sticking to my Google Pay and Revolut combination though; it works great.

EDIT – Here’s a demo of the BOV PAY in real life – note how long it takes for the BOV APP to trigger (and show up) after payment takes place.

Store your MySQL Docker database info in a Docker Volume

If you spin a MySQL Docker container, you’ll notice that once the container is stopped, all the information is lost! In order not to lose any information from your MySQL Docker database, a volume will need to be attached to the container. Let’s do that!

Let’s create a new volume – this will be used to store all your database informaton

docker volume create mysql

Once the volume is created, it can be attached to a newly spun MySQL container

docker run --name mysql -e MYSQL_ROOT_PASSWORD=albert --mount source=mysql,target=/var/lib/mysql -d mysql

Any datatabses created on this MySQL instance is now preserved! Let’s test it out. Let’s connect to the container and create a new database:

docker exec -it mysql mysql -uroot -p

Supply your password (in this example, the password would be the value that we’ve supplied for the MYSQL_ROOT_PASSWORD – albert

Once you’re connected, let’s see the current databases. The default installation will have 4 default databases

SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

Let’s go ahead and create a new database!

CREATE DATABASE test;

If you get all the databases now, you should get the following

SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+

De-attach from MySQL – type exit. Let’s now remove the current container and re-create a new container; re-attach the previously created volume.

docker container rm mysql -f
docker run --name mysql -e MYSQL_ROOT_PASSWORD=albert --mount source=mysql,target=/var/lib/mysql -d mysql

Let’s re-attach and get the list of databases (don’t forget to supply the password):

docker exec -it mysql mysql -uroot -p
SHOW DATABASES;

The output should now read as follows – the database test still exists, even after deleting and re-creating the container

+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+

How to get your first Docker container up and running on Ubuntu in 2 minutes or less

Looking to install Docker and to play around a bit? If you follow the main guide on the Official Docker site, you’ll be surprised how many steps need to be taken to get Docker Installed.

Thankfully, if you keep scrolling, you’ll notice that there is a convenience script! That’s great! Let’s get Docker installed!

Make sure you got cURL installed:

sudo apt-get install curl

Then let’s use the convenience script to install Docker!

sudo curl -sSL https://get.docker.com/ | sh

Once the installation is complete, let’s get your first container running!

sudo docker run hello-world

This should show something along the lines of:

Hello from Docker!
This message shows that your installation appears to be working correctly

Then it means that your installation is now complete!

You can already use Google Pay in Malta!

UPDATE: Some users have reported that Revolut was not allowing them to add cards to their Google Pay accounts in Malta. So, your mileage may vary. Users whose cards are already added will still work fine. This was working as intended at the moment of writing.

Unless you have been living under a rock, you’ll know that Apple Pay is now supported in Malta, through Revolut. But little did Android users know that Google Pay has been supported by Revolut for more than a year now!

According to an article on Android Police, around mid-July 2018, Revolut rolled out support for Google Pay. This means that using any NFC enabled Android device, you can start paying locally with your phone!

What is Revolut?

Revolut is an online bank based in the UK – you can get a free debit card to be used locally and comes with a great Android app. It’s the only card that works with Google Pay in Malta – BOV, HSBC, BNF and any other local bank do not support Google Pay, so Revolut is your only choice in this case. You can sign up with Revolut for free here (note that with each successful sign-up, I get a small kick-back, as described here).

How to I get Google Pay?

Easy – using your Android Phone, just search for Google Pay on Google Play: https://play.google.com/store/apps/details?id=com.google.android.apps.walletnfcrel

Can’t find the app on the store, or it says something like “This app is incompatible with all of your devices”? Just download the APK from some APK Mirror, like https://apkpure.com/google-pay-pay-with-your-phone-and-send-cash/com.google.android.apps.walletnfcrel. Of course, side-loading applications can be risky so proceed with caution.

revolutgooglepay

How do I add my card?

Adding the card is very easy – just follow the setup on screen. If you ever used your Revolut card with Google, you’ll find it right there. If not, just add your details. Have your Card No, Expiry Date and CVV at hand though. You’ll need to confirm a code by SMS as well. No screenshots for this section as Google Pay doesn’t allow you to take screenshots when adding cards. You can find a video guide here – https://www.youtube.com/watch?v=7zS6aR22QZM

Anything I should know?

Yes – keep in mind that these transactions are considered Online transactions. Therefore, you’ll need to enable Online Transactions in the Card Security section. Don’t worry, if it’s turned off by default, Revolut will warn you about this.

onlinetransactionsrevolut

How will my transactions appear?

This is the nice part – they will show up like all other transactions. The payment will not be towards Google; it will point to the retailer you’ve just purchased from.

revoluttransaction

How can I use Google Pay to pay?

Very easy! Firstly, make sure that NFC is turned on. Then, just unlock your phone and tap the payment machine when the retailer asks you to do so. Your phone will vibrate when you get tour phone close enough and Google Pay will activate itself. You may be asked to verify your identity, such as by supplying a PIN, Fingerprint or lock pattern. By, the way, lock patterns are bad and you should avoid them.

Take that, Apple Pay!

C# Micro Optimizations Part 2 – In Parameter Modifier

In this series of posts, we’re investigating micro-optimizations in C#. As previously mentioned, these may not be applicable to all; but it’s still fun looking at these concepts.

Let’s visit back the last post – Ref arguments. Ref arguments gave us the power of passing structs by value in an extremely efficient manner.

Mutability of a ref struct

Passing structs by ref brings a major disadvantage – the callee might mutate the value of the struct without the caller ever knowing. What if we need to pass structs in an efficient manner, whilst having peace of mind that the callee doesn’t mutate the struct?

Meet the in parameter modifier- C# 7.2

What does the in parameter modifier do? It allows us to pass the argument by reference and giving us the guarantee that the arguments cannot be modified by the callee. Excellent! Let’s run a quick test and make sure our performance is still comparable when passing by ref. Let’s have a struct with 2 properties – let’s have some work done using two different methods – passing by ref and passing by in.

All code can be viewed here – https://github.com/albertherd/csharpmopt2-in

public class SixteenBitStructBenchmark
{
    [Benchmark]
    [Arguments(100000000)]
    public void BenchmarkIncrementByRef(int limit)
    {
        SixteenBitStruct sixteenBitStruct = new SixteenBitStruct();
        int counter = 0;
        do
        {
            IncrementByRef(ref sixteenBitStruct);
            counter++;
        }
        while (limit != counter);
    }

    [Benchmark]
    [Arguments(100000000)]
    public void BenchmarkIncrementByIn(int limit)
    {
        SixteenBitStruct sixteenBitStruct = new SixteenBitStruct();
        int counter = 0;
        do
        {
            IncrementIn(sixteenBitStruct);
            counter++;
        }
        while (limit != counter);
    }

    private void IncrementByRef(ref SixteenBitStruct sixteenBitStruct)
    {
        double sum = sixteenBitStruct.D1 + sixteenBitStruct.D2;
    }

    private void IncrementIn(in SixteenBitStruct sixteenBitStruct)
    {
        double sum2 = sixteenBitStruct.D1 + sixteenBitStruct.D2;
    }
}

public struct SixteenBitStruct
{
    public double D1 { get; }
    public double D2 { get; }
}

Let’s see how they perform.

Method limit Mean Error StdDev
BenchmarkIncrementByRef 100000000 23.83 ms 0.0272 ms 0.0241 ms
BenchmarkIncrementByIn 100000000 238.21 ms 0.3108 ms 0.2755 ms

Performance loss?

Wait a second – why is IncrementByIn 10x slower than IncrementByRef when we’re accessing 2 properties in the same struct? Let’s have a look at the generated IL.

IncrementByRef

 IL_0000: ldarg.1
IL_0001: call instance float64 InOperator.SixteenBitStruct::get_D1()
# Loads argument 1 (SixteenBitStruct) and call the getter

IncrementByIn

 IL_0000: ldarg.1
# Prepare a new local variable on the evaluation stack
IL_0001: ldobj InOperator.SixteenBitStruct
# Copies the value of SixteenBitStruct into the loaed argument variable
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call instance float64 InOperator.SixteenBitStruct::get_D1()
# Pops the newly created argument into location 0, loads local variable 0 (new copy of SixteenBitStruct) and call the getter

Interesting! When we’ve called the method by ref, the resultant IL just loads the argument and calls the getter. When we’ve called the method by in, the resultant IL creates a copy of the struct before the getter is called. It seems that each time we’re referencing the property, C# is generating a copy of the object for us? We’re facing a by-design feature – a defensive copy.

Why do we encounter a defensive copy?

When calling the getter of our properties, the compiler doesn’t know if the getter mutates the object. Although this is a getter, it’s only by convention that changes aren’t made; there is no language construct that prevents us from changing values in our getter. The compiler must honor the in keyword and generate a defensive copy, just in case the getter modifies the struct.

In the end of the day, a getter is just syntactic sugar for a method. Of course, defensive copies will be generated if methods are called on the struct since the compiles can’t provide any guarantee that the method call won’t mutate the struct.

How do we get around this?

We’ll need instruct the compiler that our struct is immutable, so the compiler doesn’t need to worry about creating defensive copies since values cannot change. C# provides this exact functionality in fact! We can slap the “readonly” keyword (and drop any setters) so that we can guarantee that our struct is now immutable.

Here’s how it looks now

 public readonly struct SixteenBitStruct
{
    public double D1 { get; }
    public double D2 { get; }
}

Revisiting our performance numbers

Let’s re-run our benchmarks and assess the performance.

Method limit Mean Error StdDev
BenchmarkIncrementByRef 100000000 23.93 ms 0.1226 ms 0.1147 ms
BenchmarkIncrementByIn 100000000 24.06 ms 0.2183 ms 0.2042 ms

Far better! Performance is now equal (within margin of error). Some closing thoughts about this:

  • Using the in operator is an excellent feature – it allows the callers to safely assume that the values they are going to pass will not have their values changed.
  • Using the readonly modifier with a struct is another excellent feature – it allows the the developer to safely say that its value is immutable and no changes are allowed.
  • The performance uplift is should be considered as a bonus – the design and infrastructure wins using the in / readonly keywords in these context carry far more value.
  • Don’t ever use the in keyword in conjunction with non-readonly structs. Chances are that the performance gained from passing by ref will be lost by accessing the struct’s properties and methods.

Until the next one!

C# Micro Optimizations Part 1 – Ref Arguments

In this series of posts, we’ll be investigating key areas for micro-optimizations. As the title implies, these are micro-optimizations and may not be applicable for you unless you are writing some high-performance library of have a piece of code running in a tight loop. Nonetheless, it’s still fun to investigate and find these micro-optimizations. Onwards!

Let’s start with a simple one – the ref keyword in method arguments. For this argument, we’re only concerned with value type method arguments – structs.

Since structs are value types, by default, the entire struct is copied over to the callee, irrelevant of the size of the struct. If the struct is big, this is typically a bottleneck since a copy must be created and passed for each call. C# provides a method of overriding this behavior by using the ref keyword. If an argument is marked as ref, a pointer to the struct will be passed rather than an actual copy!

This brings two major advantages:

  • If the struct is bigger than 4 bytes (on a 32 bit machine) or 8 bytes (on a 64 bit machine), passing a struct by ref means that less data copying is taking place.
  • We avoid copying back the data – we do not need to return the data since a reference is passed rather than a copy of the struct.

Let’s see an example – lets consider a struct containing two doubles – a 16 byte struct. Let’s say we have two methods that increments one of the values for us (just to give the loop something to do and not get it optimised away).

One of them accepts a (copy of a) struct, increments its internal values and returns the copy back. This is passed by value, which is the default behavior for a struct.

The other method accepts a struct by ref and increments its internal values. There is no need to return the data back therefore no extra copies were needed. This is not the default behavior, so we’ll need to accompany it with the ref keyword.

The below is the source code in question – find the whole solution here: https://github.com/albertherd/csharpmopt1-ref

[CoreJob]
public class SixteenBytesStructBenchmark
{
    [Benchmark]
    [Arguments(1000000)]
    public void BenchmarkIncrementByRef(int limit)
    {
        SixteenBytesStruct value = new SixteenBytesStruct();
        int counter = 0;
        do
        {
            IncrementByRef(ref value);
            counter++;
        }
        while (limit != counter);
    }
    [Benchmark]
    [Arguments(1000000)]
    public void BenchmarkIncrementByVal(int limit)
    {
        SixteenBytesStruct value = new SixteenBytesStruct();
        int counter = 0;
        do
        {
            value = IncrementByVal(value);
            counter++;
        }
        while (limit != counter);
    }
    private void IncrementByRef(ref SixteenBytesStruct toIncrement)
    {
        toIncrement.d0++;
    }
    private SixteenBytesStruct IncrementByVal(SixteenBytesStruct toIncrement)
    {
        toIncrement.d0++;
        return toIncrement;
    }
}
public struct SixteenBytesStruct
{
    public long d0, d1;
}

The below is the time taken for 1000000 runs – this was executed using .NET core 2.2.1 – benchmarks done using BenchmarkDotNet

Method limit Mean Error StdDev
BenchmarkIncrementByRef 1000000 1.663 ms 0.0139 ms 0.0130 ms
BenchmarkIncrementByVal 1000000 2.872 ms 0.0155 ms 0.0145 ms

We can see that running this in a tight loop, doing the work by ref, in this case, is 72% faster! To what can we attribute this performance change? Let’s have a look at what’s happening behind the scenes.

Doing the work by value

Calling IncrementByVal

IL_000a: ldarg.0 # Load the “this” parameter on evaluation stack (implicit)
IL_000b: ldloc.0 # Load SixteenBytesStruct value on the stack (16 bytes worth of data) from location 0
IL_000c: call instance valuetype Ref.SixteenBytesStruct Ref.SixteenBytesStructBenchmark::IncrementByVal(valuetype Ref.SixteenBytesStruct) # Call IncrementByVal with the loaded arguments
IL_0011: stloc.0 #Captures the returned value and stores it in location 0

IncrementByVal Implementation

IL_0000: ldarga.s toIncrement # Load the argument’s address so processing can begin
..method work – removed for brevity
IL_001a: ldarg.1 # Load the value of the field back so it can be returned
IL_001b: ret

What’s happening here?

  • Push the value of SixteenBytesStruct ready to be captured by the upcoming method call
  • Call IncrementByVal
  • IncrementByVal loads the address of the received value from the caller and does the required work
  • Push the value of the SixteenByteStruct after the work has been done ready to be captured by the caller
  • IncrementByVal Returns
  • Pop the value from replace the value of SixteenBytesStruct with the new one

Doing the work by ref

Calling IncrementByRef

IL_000a: ldarg.0 # Load the “this” parameter on evaluation stack (implicit)
IL_000b: ldloca.s V_0 # Load SixteenBytesStruct’s address on the stack (8 bytes worth of data)
IL_000d: call instance void Ref.SixteenBytesStructBenchmark::IncrementByRef(valuetype Ref.SixteenBytesStructamp;) # Call IncrementByVal with the loaded arguments

IncrementByVal Implementation

IL_0000: ldarg.1 # Load the argument so processing can begin. We’re not calling ldarga.s since this already the struct’s address rather than the actual value
..method work – removed for brevity
IL_0018: ret # Return

What’s happening here?

  • Push the address of SixteenBytesStruct ready to be captured by the upcoming method call
  • Call IncrementByVal
  • IncrementByVal gets value received from the caller (the value is an address) and does the required work
  • IncrementByVal Returns

What does this mean?

One can obviously note that doing the work by ref has significantly less work to do:

  • The callee is pushing 8 bytes instead of 16 bytes
  • The callee loads 8 bytes onto the evaluation stack instead of 16 bytes
  • The callee doesn’t need to push the new value onto the evaluation stack
  • The callee doesn’t need to pop the stack and stored the updated value

Therefore, doing the work by ref is pushing less data when a method call takes place (maximum of 8 bytes, irrespective of the struct size) and is avoiding two data copy instructions, since it does not need to push and pop the new value since there are no return values.

If you increase the size of the struct, the performance gains would be even bigger, as shown in the below graph.

C#RefBenchmark

We can observe some useful information from this graph

  • When it comes to doing operations by ref, performance is basically equivalent all cross the board, irrelevant to the size of the struct.
  • 16 byte, 8 byte and 4 byte structs carry identical performance – they are just separated by the margin of error.
  • 16 byte, 8 byte and 4 byte structs are faster than 2 byte and 1 byte structs. In fact, 1 byte struct ends up clearly slower than a 2 byte struct! It’s very interesting to explore why 1 and 2 byte structs exhibit performance degradation.
  • The rest of the result show a consistent upward trend – which reflect the amount of data copying take place.

What’s very interesting is that a 4 byte integer operates faster by value when compared to 1 byte and 2 byte integers!

Tag your photo album using Microsoft Cognitive Services

Just interested in the source code? – https://github.com/albertherd/PhotoTagging

Computer vision is one of the key areas that has seen huge growth in both capability and popularity. Though it seems that it’s still out of reach to many; I honestly felt lost when I was trying to play around in this field. It feels like we’re trying to solve problems which have already been solved by other companies. It seems Microsoft shares this vision though, as they’ve introduced Machine Learning features in the form of SaaS.

I’ve stumbled upon Microsoft Cognitive Services through a presentation and I was genuinely amazed. What’s amazing isn’t the results that this service yields – I’ve expected nothing less than excellent results from such tools. What amazed me is how EASY to get involved – there is no fiddling with following pages and pages of guides just to download, install and play around with some software.

Microsoft Cognitive Services enables you to do a huge array of Machine-Learning powered applications, ranging from vision, decision making, natural language processing and other areas. Let’s play around vision – can we use Microsoft’s Cognitive Vision Services and help us organise our photo library?

The idea is that I have many photos, with subjects ranging from food, vacation, family, friends and whatnot. What if my photos contain the proper EXIF tags such as subject and tags? This will allow me to classify my photos by subject and allow me to search through them. What if I can find my photos instantly instead of sifting manually through thousands of photos? I’ll presume that it’s not just me though, everyone has a smartphone nowadays, so this is everyone’s pain.

Great – now we have an objective! Let’s make the tools work for us now. The process will be simple – upload a photo to Microsoft’s Cognitive Vision Services, get the tags and a nice description and slap it to the actual file. Oh, when I say EXIF tags, these can be viewed in File Explorer like below. (Windows 10 Dark Theme in File Explorer here)

ExifInWindowsExplorer

Ready to tag your photo library? Let’s go!

Get a Microsoft Cognitive Services Account

Since this is an online service, you’ll need to have an active account with Microsoft Azure. Get your free account from here. Don’t worry, the free service is more than enough to get you playing around. I’ve used the free tier to develop, test and write this blog and I still have plenty of free capacity left.

Create a new Cognitive Services Resource and get the API key

Now that you have an active Azure account, navigate to the Azure Portal and create a new Cognitive Services Resource. Follow the wizard and get the service created – choose whatever region works best for you. I’ve chosen West Europe and the free tier in my case. Once it’s created, we’ll need two things – the URL to our endpoint and our API Key. From the quick start page, get API endpoint and the API Keys.

Get your photos tagged!

Okay, we got all the resources needed, it’s time to get some work done! I’ve created an application to get a photo, upload it our new Cognitive Services resource, get tags and description and apply it to our photo.
Follow these steps to get your photo tagging game going!

  1. Download / Clone my application from GitHub
  2. Open the application and navigate to PhotoAnalyser.cs. Change the subscriptionKey and uriBase to the ones you got previously. The keys in the solution are placeholder keys only.
  3. Run the application – have your photo directory ready as this is asked for at runtime.
  4. Let it do its magic!

In the below example, photo analysis tells us that it’s a pizza on a plate and it also gave us some appropriate tags. Try downloading and viewing the pizza photo -tags and title are preserved as EXIF data.

Keep in mind that the code in the provided solution is not production ready – it’s merely meant as a playground.

Explore the solution

What’s the fun of having a piece of software working without knowing how it works underlying? Here are some points about the application, in no particular order:

  1. It’s making one of the excellent TPL Dataflow framework from Microsoft – this enables the application to scale with ease and to work around the pesky throttling that the free tier carries with it.
  2. It is resizing the images since they don’t need to be large, plus this speed the process up.
  3. It’s using the ImageSharp to resize and add Exif tags to the images.
  4. Given that this application is manipulating images, it is memory intensive. I’ve seen this image hit close to 4GB in memory usage.
  5. It’s split into a library and a consumer just in case.

Continue exploring the Microsoft Cognitive Services stack

Computer vision is just one of the areas in the Microsoft Cognitive Services stack; there are other excellent services to enrich your applications. They also have excellent documentation on this; I’ve followed this to build my application.

That’s it for today! This was an extremely fun project to learn and experiment with new technologies! Until the next one.

Outputting DS18B20 temperatures on a LCD1602 – Raspberry Pi Temperature Monitoring Part 4

This is part of a tutorial series. If you feel a bit lost, I suggest following the tutorial in order:

Just interested in the code? – https://github.com/albertherd/DS18B20Reader

This article assumes that you’ve configured one or more DS18B20 sensors to your Raspberry Pi and configured your Raspberry Pi to work with an LCD1602. If you did not, read the above mentioned links.

Okay – this should be a quick post – most of the heavy lifting is done. Remember the LCD1602 library that we’ve used in the second tutorial? We’ll be using that to simply get the temperature we’ve captured in third tutorial and display it.

We’ll need to do the following changes:

  1. Import the LCD1602 library.
  2. Initialize the LCD1602 on application startup.
  3. Read and display information on the LCD1602.
  4. Cleanup resources before exiting – this is important since we’ll need to turn off the backlight after usage.

Import the LCD1602 library

Get a copy of this repository – either by cloning or simply copying lcd1602.c and lcd1602.h files to your solution. We’ll be also adding them to our CMake file – it should look something of the sort. I’ve left the solution on debug in this case.

set(SOURCE main.c sensor.c lcd1602.c main.h sensor.h lcd1602.h)
set(CMAKE_BUILD_TYPE Debug)
add_executable(DS18B20Reader ${SOURCE})

Now it’s simply just adding a reference to the lcd1602.h in the solution. Next!

Initialize the LCD1602 on application startup

We’ll need to initialize the library and open a connection to the display under the right address – check your device address by checking the third tutorial. To simplify things, I hard-coded the value which is 0x27 in my case. Call this when initializing the application.

void InitializeLCD()
{
    int rc;
	rc = lcd1602Init(1, LCDADDRESS);
	if (rc)
	{
		printf("Initialization failed; aborting...\n");
		return;
	}
}

Read and display information on the LCD1602

We’ll be modifying our main loop to output content to the console (not important though and output to the LCD1602 screen. The main adjustment we’ve did in the main loop is that we’ve broken down our output to two functions – Outputting to console (not important) and outputting to the LCD1602 – Let’s see the main loop:

void ReadTemperatureLoop(SensorList *sensorList)
{
    while(!sigintFlag)
    {
        for(int i = 0; i SensorCount; i++)
        {
            float temperature = ReadTemperature(sensorList->Sensors[i]);
            PrintTemperatueToLCD1602(sensorList->Sensors[i], i % LCD1602LINES, temperature);
            LogTemperature(sensorList->Sensors[i], temperature);
        }       
    }
}

Let’s now have a look at the important method – PrintTemperatueToLCD1602. Keeping in mind that the LCD1602 has two lines, we’ll be receiving the calculated line number as a parameter. This will make sure that values will lie between 0 and 1 only using modulus.

We’ll also need to remember that each line will hold up to 16 characters, so we’re truncating anything more than 16 characters (actually 16 + 1 for null termination). We’ll then just pass the (potentially truncated) string to the LCD1602 and et voila!

void PrintTemperatueToLCD1602(Sensor *sensor, int lineToPrintDataOn, float temperature)
{
    char temperatureString[LCD1602CHARACTERS + 1];
    snprintf(temperatureString, LCD1602CHARACTERS + 1, "%s : %.2fC", sensor->SensorName, temperature);

    lcd1602SetCursor(0, lineToPrintDataOn);
    lcd1602WriteString(temperatureString);
}

Cleanup resources before exiting

After we’re done, it’s just a matter of cleaning up resources. As previously mentioned, this is important since we’ll need to turn off the backlight after usage. In the cleanup method, we’re just calling the lcd1602Shutdown method.

void Cleanup(SensorList *sensorList)
{
    printf("Exiting...\n");
    FreeSensors(sensorList);
    lcd1602Shutdown();
}

Fetch a complete copy of the code from from GitHub – https://github.com/albertherd/DS18B20Reader

Let’s run the application! In a terminal with git and cmake installed, run the following commands

git clone https://github.com/albertherd/DS18B20Reader
cd ./DS18B20Reader
cmake . && make && ./DS18B20Reader "Sensor"

With some luck, your LCD1602 should display something like the below. In my case I have two sensors so I’ve fired up the application using the following syntax:

./DS18B20Reader "Sensor1" "Sensor2"

LCD1602OutputCropped

Until the next one!

Using C to monitor temperatures through your DS18B20 thermal sensor – Raspberry Pi Temperature Monitoring Part 3

This is part of a tutorial series. If you feel a bit lost, I suggest following the tutorial in order:

Just interested in the code? – https://github.com/albertherd/DS18B20Reader

Since you made it here, great! Your Raspberry Pi should have one or more DS18B20 thermal sensors connected, like the image below.

sensor2.png

Now that we have our DS18B20 thermal sensor connected to our Raspberry Pi, it’s time to do some programming to read out the temperature! Our application will need to be able to the following tasks:

  1. Discover all the DS18B20 sensors (in my case, I’ve connected 2 but this application should handle an arbitrary number of sensors).
  2. Assign a friendly name so we’ll know which sensor is which and store them in a list.
  3. Retrieve and parse the information from the device.
  4. Do whatever necessary with the gathered information.

1) Discover all the DS18B20 sensors

First and foremost, our code cannot just assume that devices just exist on the system – we’ll need to go and discover these devices. Since the DS18B20 makes use of the 1-Wire protocol, devices will live under the /sys/bus/w1/devices/ directory. Therefore, our code will need to devices living under this directory, whose names start with 28 since all DS18B20 device names will start with 28. Let’s start by knowing how many devices are connected.

typedef struct Sensor
{
    char *SensorName;
    FILE *SensorFile;    
} Sensor;
 
typedef struct SensorList
{
    Sensor **Sensors;
    int SensorCount;
} SensorList;

DIR *dir;
struct dirent *dirEntry;

SensorList *sensorList = malloc(sizeof(SensorList));
sensorList->SensorCount = 0;

if(!(dir = opendir("/sys/bus/w1/devices/")))
    return sensorList;

while((dirEntry = readdir(dir)))
{        
    if(strncmp(dirEntry->d_name, "28", 2) == 0)
    {
        sensorList->SensorCount++;
    }
}

2) Assign a friendly name so we’ll know which sensor is which and store them in a list

Now that we’ve discovered the devices connected to the system, it’s time to save a reference and optionally a friendly name as well. Logic mostly applies from step 1.

sensorList->Sensors = malloc(sizeof(Sensor*) * sensorList->SensorCount);
Sensor **currentSensor = sensorList->Sensors;   

int sensorNamesAllocated = 0;
while((dirEntry = readdir(dir)))
{        
    if(strncmp(dirEntry->d_name, "28", 2) == 0)
    {   
        char *sensorName;
        if(sensorNamesCount > sensorNamesAllocated)
        {
            sensorName = strdup(*sensorNames);
            sensorNames++;
        }
        else
        {
            sensorName = strdup("Sensor");
        }

        char sensorFilePath[64];     
        sprintf(sensorFilePath, "%s%s%s",  "/sys/bus/w1/devices/", dirEntry->d_name, "/w1_slave");
        *currentSensor = GetSensor(sensorFilePath, sensorName);
        currentSensor++;
    }
}

Sensor *GetSensor(char *sensorId, char *sensorName)
{
    Sensor *sensor = malloc(sizeof(Sensor));
    sensor->SensorFile = fopen(sensorId, "r");
    sensor->SensorName = sensorName;
    return sensor;
}    

3) Read the temperature from the device

This is the most exciting part – we actually get to read the temperatures! Using the sensor information we got from steps 1 and 2, we can get the device, open it as a file, extract the readings and parse it accordingly. Using the FILE API makes it very easy to do so – grab all the contents and store it in a buffer. As mentioned in the first tutorial, the content of the file looks as follows –

0b 01 55 05 7f 7e 81 66 bf : crc=bf YES
0b 01 55 05 7f 7e 81 66 bf t=16687

We’re only intereested in the t= component, so some string manipulation and float conversion will take the 16687 and convert it into 16.687C. We’re also doing some range checking since the DS18B20 is rated between -55C and +125C

   
long deviceFileSize;
char *buffer;

FILE *deviceFile = sensor->SensorFile;
fseek(deviceFile, 0, SEEK_END);
deviceFileSize = ftell(deviceFile);
fseek(deviceFile, 0, SEEK_SET);

buffer = calloc(deviceFileSize, sizeof(char));

fread(buffer, sizeof(char), deviceFileSize, deviceFile);
char *temperatureComponent = strstr(buffer, "t=");
if(!temperatureComponent)
{
    free(buffer);
    return -1;
}

temperatureComponent +=2; //move pointer 2 spaces to compensate for t=

float temperatureFloat = atof(temperatureComponent);
temperatureFloat = temperatureFloat / 1000;

if(temperatureFloat  125)
    temperatureFloat = 125;    

free(buffer);
return temperatureFloat;

4) Do whatever necessary with the gathered information

We now have the information at hand, great! We can do many sort of things with it, such as sending an email, activating some other device or whatever is necessary. For demo purposes, we’re simply going to output the contents to the console just to see it working. This is in a loop so we’ll keep reading the temperature until the application exits.

 while(1)
    {
        for(int i = 0; i SensorCount; i++)
        {
            char dateTimeStringBuffer[32];
            strftime(dateTimeStringBuffer, 32, "%Y-%m-%d %H:%M:%S", localtime(¤tTime));

            float temperature = ReadTemperature(sensorList->Sensors[i]);
            printf("%s - %s - %.2fC\n", dateTimeStringBuffer, sensorList->Sensors[i]->SensorName, temperature);
        }       
    }

To try out the code as a whole solution, grab a copy from GitHub – https://github.com/albertherd/DS18B20Reader

In a terminal with git and cmake installed, run the following commands

git clone https://github.com/albertherd/DS18B20Reader
cd ./DS18B20Reader
cmake . && make && ./DS18B20Reader "Sensor"

If the output looks like the below, congratulations!

ds18b20 tutorial sample output.png

In the next tutorial, we’ll pick up from here and we’ll start outputting the content on an LCD1602! Until the next one.

Connecting a LCD1602 with an I2C module to your Raspberry Pi – Raspberry Pi Temperature Monitoring Part 2

The LCD1602 is a very famous LCD that can be connected to various devices such as the Raspberry Pi. The LCD1602 on its own is quite tricky to wire it up since it requires 16 pins to be connected. The LCD1602 can also be purchased with an I2C module, which reduces the amount of pins needed to just 4.

For this tutorial, we’ll be working with a LCD1602 with an I2C module. I got mine from AliExpress for around $2.50. Make sure to grab a set of jumper cables as you’ll need them to connect the LCD to the Raspberry Pi. I got mine from AliExpress as well for around $1.50.

IMG_20190102_110607.jpg

img_20190109_230900

Let’s start by wiring it up. We have 4 pins connect – GND (ground), VCC (power, 5V), SDA (data line) and SCL (clock line). GND and VCC can be connected to any equivalent GND and 5V pin. SDA and SCL should be connected to pins BCM 2 and BCM 3 accordingly.

lcd1602_i2c_raspberrypi

img_20190109_231321

If you’re following the Raspberry Pi Temperature Monitoring Part 1 and connected the DS18B20 temperature sensors, you should now have the following configuration.

lcd1602_i2c_ds18b20_raspberrypi

img_20190109_232649

Great! We’re done from the hardware’s side – let’s start configuring our Raspberry Pi to communicate with our LCD.

Firstly, let’s enable I2C from the Raspberry Pi Config. Fire up the raspi-config to get started: sudo raspi config

Now navigate to Interfacing Options => I2C => Enable I2C

raspi-config-interfacing-options

raspi-config-interfacing-options-i2c

Now that we’ve enabled I2C communication, it’s time to start development! We’ll need to get some tools before we start working though, so fire up a shell and input:

sudo apt-get install i2c-tools.

Once that’s done, the LCD is ready to be programmed! Let’s make sure that the LCD is properly connected and working. In a shell, type:

i2cdetect -y 1.

The output should be something like the below. Note the number outputted by the command; will be needed later on. We’ll need this address when we’re trying our demo code. In this case, the address is “27”.

i2cdetect

Great! Now, it’s time to test out our display and see if it works! We’ll be using a Github library – https://github.com/albertherd/LCD1602. This has been forked from https://github.com/bitbank2/LCD1602. We’ll be using my fork since the original repository has an unresolved issue with clearing the display.

After you’ve cloned the repository in your working directory, it’s time to use the address (27 in my case) obtained earlier. Open the main.c and find the call to lcd1602Init and change second parameter. This is how it looks in my case:

lcd1602Init(1, 0x27);

Now it’s time to compile and run our code. If all goes well, we should be getting some text on the screen. You can change the text to whatever you’d like by changing the following lines in main.c.

lcd1602WriteString("BitBank LCD1602");
lcd1602SetCursor(0,1);
lcd1602WriteString("ENTER to quit");

Build and run using the following commands:

make
make -f make_demo
./demo

The screen should look like the below:

IMG_20190110_231937.jpg

Great! Now we’ve successfully connected our LCD1602 to our Raspberry Pi and we’re able to output content on it!

In the next part of this tutorial series, we’ll start by capturing the temperature using the sensor in our first part of the tutorial and outputting it! Stay tuned.