This is my sixth blog post covering Windows 10 IoT Core.
Previous posts:
Part 1: https://blogs.perficient.com/microsoft/2016/01/windows-10-iot-editions-explained/
Part 2: https://blogs.perficient.com/microsoft/2016/01/iot-development-with-windows-10-and-raspberry-pi-what-you-need/
Part 3: https://blogs.perficient.com/microsoft/2016/01/iot-development-with-windows-10-and-raspberry-pi-setting-up/
Part 4: https://blogs.perficient.com/microsoft/2016/01/iot-development-with-windows-10-and-raspberry-pi-hello-world/
Part 5: https://blogs.perficient.com/microsoft/2016/01/iot-development-with-windows-10-and-raspberry-pi-public-display/
In previous blog post we development a Raspberry Pi 2 application which could be used to present a slideshow on a big public display (outdoor or indoor). That application was pulling images in real time from Flickr feed (to emulate a real image source). The problem with this approach is that application requires a constant internet connectivity, which may not be a case for a public display. The more realistic use case for such application is the following: it got connected to internet (or LAN) only for some period of time to upload images on devices. Then the device was disconnected and used offline for displaying images from local storage.
So, we need to implement the following:
– Check internet/network connectivity
– Synchronize local image storage with images on the network (i.e. load images from network to load storage)
– Display images from local storage
The most common way to storage anything on a low power device like Raspberry Pi is to use SQLite. SQLite a popular library (not database server) for mobile, low power devices which allows application to store date in structured relational storage and query that data with SQL. Fortunately, there is a port of this library to Windows Universal platform and hence to Raspberry Pi.
These are the steps to add SQLite support to your Raspberry Pi project:
- Install SQLite extension for Visual Studio 2015 for Universal App Platform (UAP) from here: http://sqlite.org/download.html. File name is sqlite-uap-3100100.vsix.
- Install SQLite.NET-PCL NuGet package (type Install-Package SQLite.Net-PCL in NuGet package manager console).
- Add reference to the extension downloaded to step 1 and Visual C++ 2015 Runtime for UAP (you’ll need to select Add References and then choose Universal Windows -> Extensions):

Now we all set up to use SQLite in our IoT application.
First, we need to define a schema for a table where we going to to be storing our images. Just like with Entity Framework Code First, we can do this by creating an entity model class (underlying table is going to be generated automatically):
public class StoredImage
{
///
/// Image ID
///
[PrimaryKey, AutoIncrement]
public int ImageID { get; set; }
///
/// Image itself as BLOB
///
public byte[] Image { get; set; }
}
Note the [PrimaryKey] and [AutoIncrement] attributes above. They are telling SQLite framework that ImageID is going to be a primary key for StoredImage table.
Then, we need to modify our Flickr reader. In our previous example FlickrReader was preloading image names into local memory array and then was returning images one by one to caller. In this example we need to store images in local database, so it would make more sense to return all image references to caller at once:
public sealed class FlickrReader
{
private const string FeedBaseUrl = "https://api.flickr.com/services/feeds/photos_public.gne";
private readonly string _tags;
public FlickrReader(string tags)
{
_tags = tags;
}
public async Task<ienumerable> GetImages()
{
// build request to flickr image feed
var url = FeedBaseUrl + "?tags=" + _tags;
// load image feed
var feed = await XmlDocument.LoadFromUriAsync(new Uri(url));
// parse out images from ATOM 1.0 feed
var images = feed
.DocumentElement
.ChildNodes
.Where(n => n.NodeName == "entry")
.SelectMany(n => n.ChildNodes)
.Where(n => n.NodeName == "link")
.Where(l => l.Attributes.Any(a => a.NodeName == "rel" && (string)a.NodeValue == "enclosure"))
.SelectMany(e => e.Attributes.Where(a => a.NodeName == "href")
.Select(a => (string)a.NodeValue))
.ToList();
return images;
}
}
We also need to know if we are connected to network, so we are able to load images into our local database:
public class InternetConnectivity
{
public static bool IsConnected()
{
ConnectionProfile connections = NetworkInformation.GetInternetConnectionProfile();
return
connections != null
&& connections.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess;
}
}
Now the new fun part: downloading images locally and storing them to the database:
public sealed class ImageLoader
{
private int? _currentImageIdx = null;
private bool _isWritingImages = false;
private SQLiteConnection GetConnection()
{
var dbPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, "db.sqlite");
return new SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), dbPath);
}
///
/// Return next image from database
///
///
public byte[] GetNextImage()
{
try
{
// get SQLite connection
using (var conn = GetConnection())
{
// get table reference
var table = conn.Table();
// select image ids
var ids = table.Select(i => i.ImageID).ToList();
int? imageID = null;
if (!ids.Any())
{
return null;
}
// get next image id
if (!_currentImageIdx.HasValue || _currentImageIdx >= ids.Count)
{
imageID = ids.First();
_currentImageIdx = 0;
}
else
{
imageID = ids[_currentImageIdx.Value];
_currentImageIdx++;
}
// select image bytes from database
return table
.Where(i => i.ImageID == imageID)
.Select(i => i.Image)
.FirstOrDefault();
}
}
catch(Exception)
{
// we may be geting database deadlocks from time to time
// because we reading and writing to the same table at the same time
return null;
}
}
///
/// Download and store images to local database
///
///
///
public async Task StoreImages(IEnumerable images)
{
if(_isWritingImages)
{
return;
}
_isWritingImages = true;
// get SQLite connection
using (var conn = GetConnection())
{
// ensure the table is created
conn.CreateTable();
// get table reference
var table = conn.Table();
// clear the table
conn.DeleteAll();
foreach (string imageUrl in images)
{
using (var client = new HttpClient())
{
// load image from Flickr into byte array
var response = await client.GetAsync(new Uri(imageUrl));
var buffer = await response.Content.ReadAsBufferAsync();
byte[] rawBytes = new byte[buffer.Length];
using (var reader = DataReader.FromBuffer(buffer))
{
reader.ReadBytes(rawBytes);
}
// create new database record
var image = new StoredImage()
{
Image = rawBytes
};
try
{
// try to insert it to database
conn.Insert(image);
}
catch(Exception)
{
// we may be geting database deadlocks from time to time
// because we reading and writing to the same table at the same time
}
}
}
}
_isWritingImages = false;
}
}
Finally, we need to wire it all together:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
var imageLoader = new ImageLoader();
// start image loading task, don't wait
var task = ThreadPool.RunAsync(async (source) =>
{
await LoadImages(imageLoader);
});
// schedule image databaase refresh every 20 seconds
TimeSpan imageLoadPeriod = TimeSpan.FromSeconds(20);
ThreadPoolTimer imageLoadTimes = ThreadPoolTimer.CreatePeriodicTimer(
async (source) =>
{
await LoadImages(imageLoader);
}, imageLoadPeriod);
TimeSpan displayImagesPeriod = TimeSpan.FromSeconds(5);
// display new images every five seconds
ThreadPoolTimer imageDisplayTimer = ThreadPoolTimer.CreatePeriodicTimer(
async (source) =>
{
// get next image (byte aray) from database
var imageBytes = imageLoader.GetNextImage();
if (imageBytes != null)
{
// we have to update UI in UI thread only
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
// create bitmap from byte array
BitmapImage bitmap = new BitmapImage();
MemoryStream ms = new MemoryStream(imageBytes);
await bitmap.SetSourceAsync(ms.AsRandomAccessStream());
// display image
splashImage.Source = bitmap;
}
);
}
}, displayImagesPeriod);
}
private async Task LoadImages(ImageLoader imageLoader)
{
// only load images when we are connected
if (InternetConnectivity.IsConnected())
{
// create Flickr reader
var reader = new FlickrReader("unicorn");
//load Flickr images
var images = await reader.GetImages();
// store images to database
await imageLoader.StoreImages(images);
}
}
}
This is what we are doing in above code:
- When application starts, we check if device is connected to internet, and if it is then we getting Flickr image feed by tag, downloading images from it and storing them in local SQLite database.
- We are also scheduling the above process to run every 20 seconds, so if we didn’t have network connectivity originally, but got connected at some point of time, then we still can load images locally.
- In parallel, we starting process which is loading images from local database and displaying them on the screen.
- Having all of the above, application is able to handle both connected and disconnected states gracefully.
Full code for this blog post is available in my Github repository: https://github.com/starnovsky/IoTDisplayWithLocalStorage
