Thursday, 9 April 2020

Growing Crystals


More lockdown science! This time we've been growing crystals!

First up plain old sodium chloride. We boiled up some water and managed to dissolve 25 teaspoons of salt into roughly 300ml of water. We then poured it into this jar and suspended some string on paperclips



Why hot water? This is because more salt can dissolve in water when it's hot than cold. We created a saturated solution while hot, and as the water cooled it became supersaturated causing the salt to start crystallizing. The string acted to provide good sites for the crystals to grow.

After a few days a good number of crystals have grown on the string. We'll keep it for longer to see how they grow.



We also got a crystal set at Christmas. This contained a packet of potassium dihydrogen phosphate, a card tree and a marker pen.

The pen was used to colour the ends of the tree branches and the solution was placed in the dish at the bottom. As the solution was raised up the card by capillary action it reached the marker ink where it started crystallizing. It also took up the colour of the ink as the powder was initially white.




And the crystals seen through the microscope. The delicate nature of these is readily apparent.


Tuesday, 31 March 2020

Static electricity and sticky balloons

With the country in lockdown due to the Covid-19 coronavirus we've been taking advantage of the time to try out some experiments.

My sons were taking great delight rubbing the balloon on their heads to get their hair to stand on end when they decided to throw it up onto the wooden ceiling beam. Where it promptly stuck.


I've often tried to stick balloons to the wall or ceiling with static electricity often with no success so this was a really good result! But, what's happening?!

When the balloon was rubbed against the hair, electrons were deposited from the hair onto the balloon. This gave it an overall slight negative charge.

Now, when the balloon touched the beam, although the beam was neutral the electrons in the balloon repelled those in the wood. This gave the surface of the wood a slight positive charge, which like a magnet will lead to positive and negative building a slight attractive force.







And what's more awesome is that the tiny amount of electric charge caused just by rubbing the balloon is enough to overcome the force of gravity from the whole Earth!


Sunday, 1 December 2019

Secure communications for the SupermarketPlanner


The SupermarketPlanner is running a Raspberry Pi Rest Server. This allows me to create a list on the Windows Client and Sync over the Internet to either another Windows Client or an Android Phone App.
As I can potentially connect these over the Internet, I wanted to setup a secure connection between my clients and server. The obvious solution to this was to setup SSL.

With SSL, a private and public key is created. The public key is distributed in the form of a certificate. This can be used to encrypt a message that can only be decrypted with the private key.
When a client connects to a server this information can be used to setup a secure connection via a hand-shake mechanism, A good explanation can be found here.

For my purposes, since I am running both client and server, I decided on setting up a self-signed certificate. I used OpenSSL on my Raspberry Pi to create this, following the steps below:

The DNS name for the server needs to be added to the Subject Alternate Name (SAN), not the CommonName (CN). The CN can be defined in the interactive request but SAN can only be defined in a separate configuration file, example below:

Self-signed certificates are not signed by a well known Certificate Authority, browsers will pop up a warning. To overcome this on my machines I added my own CA certificate to the Authorities on Chrome and Edge/IE11
  • Chrome
    •  Settings -> Advanced -> Privacy and Security -> Manage Certificates -> Authorities tab -> Import CA certificate
  • Edge / IE11
    •  Open IE11
    •  Internet Options -> Content -> Certificates
    •  Select Trusted Root Certification Authorities
    •  Click Import and choose the CA certificate to upload
Enabling SSL on the web server is simple, using web.py I just needed to add the following (This for version 0.40):

As for my client applications, after adding my CA to IE11,  SupermarketPlanner, being a .NET Core app running on Windows worked with no changes other than to use the https url. This worked on both Windows 10 and Windows 8.1 boxes.

For my Android App this was a bit more complicated. When simply changing the URL I got this Exception:

CertPathValidatorException : Trust Anchor for Certification Path not found

The documentation here: https://developer.android.com/training/articles/security-ssl was what I needed for this problem. This allows me to add my own CA to the trust chain.

I added my CA certificate to the assets/ folder in the Android project. An assets folder is a location for files that are copied as-is to the .apk file. This can then be referenced and navigated as a normal directory using the AssetManager

Thursday, 31 October 2019

Migrate Supermarket Planner to .NET Core

The SupermarketPlanner project is quite a few years old now. So given that .NET Core v3.0 has been released I thought it would be an interesting exercise to upgrade it.

My starting point for this was this Microsoft blog. (After installing .NET Core 3.0 and Visual Studio 2019.)

Portability Analyzer

The portability analyzer is a tool that reports how ready your Windows Forms or WPF application is for converting to .NET Core.

As it turns out there are two ways of getting this to run. First it can be built from this GitHub repository: https://github.com/microsoft/dotnet-apiport 

There were some points to be aware of when building this tool:
  • It needed to be build with Visual Studio 2017
  • Visual Studio Extensions support needed to be installed via the Extension manager to build a couple of the projects
  • The init.ps1 powershell script needed to be run first
The last step required Powershell to be run as admin. Also, as the script was unsigned, this command needed to be run first

    set-ExecutionPolicy RemoteSigned

The build created a .NET and .NET Core binary. Running it by default generated an Excel sheet which output of this was pretty clean, everything was supported by at least

".NET Core + Platform Extensions"

(The second way to install was using the Extension Manger in Visual Studio 2019 and load from the store. When this has been done, you can right click on the solution in Solution Explorer and select "Analyze assembly portability")

The analyzer did report problems with the unit test project. These types are no longer supported:
  • Microsoft.VisualStudio.TestTools.UnitTesting.Assert
  • Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute
  • Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute
This simplest approach was to exclude test project for the time being.

Change the project to SDK-Style

First step is to change from the old style .csproj format to the new SDK-style.
Following the steps in the blog, the new .csproj file looked like this. Much cleaner!

At this point it failed to build due to a missing reference of System.Net.Http
There was also a problem with System.Windows.Forms. These needed to be added as references

After a successful build it was now time to change to .NET Core 3! This is really simple, just change this line:

<TargetFramework>netcoreapp3.0</TargetFramework>

The project was successfully updated in Visual Studio and a new attempt made to build. This failed with a problem with System.Drawing.Print types. To be fair, this was in the analyzer report.

The fix was to add a reference to System.Drawing.Common v4.6 using NuGet.

There was one outstanding problem with print preview:

var printPreviewDialog1 = new System.Windows.Forms.PrintPreviewDialog();

The pragmatic approach was to remove this code. Supporting print preview will be a future task.

This cleared the build issues but unfortunately when starting the app I got a runtime error caused by missing images/settings.ico.

The reason for this is that icons weren't automatically added as references in the new project. manually doing this fixed the problem.

And the test project I excluded earlier? The easy way for this was to create a new unit test project and copy the tests over, referencing NUnit.Framework this time.

Azure build pipeline

I've setup an Azure build pipeline for this project but unfortunately the first build failed with this error:

##[error]ClientApp\SuperMarketPlanner.csproj(0,0):
Error : C:\Program Files\dotnet\sdk\2.2.109\Sdks\Microsoft.NET.Sdk.WindowsDesktop\Sdk not found.
Check that a recent enough .NET Core SDK is installed and/or increase the version specified in global.json.


I updated the yml file to load the 3.0.100 Sdk, But then got a failure with the NuGetCommand:

Errors in D:\a\1\s\SuperMarketPannerUnitTests\SuperMarketPlannerUnitTests.csproj
    NU1102: Unable to find package Microsoft.NETCore.App with version (>= 3.0.0)
      - Found 76 version(s) in NuGetOrg [ Nearest version: 3.0.0-preview8-28405-07 ]


For now, I've got round this by explicitly defining the latest official version for the package reference in the unit test project

<PackageReference Include="Microsoft.NETCore.App" Version="2.2.7" />

Finally, I also changed the build and test tasks in the yaml to use the DotNetCoreCLI tasks. The pipline build is now green! The updated yaml is here:

Friday, 4 October 2019

Docker Debug

When trying to start a new docker container I was getting an error from python about a missing module:

pi@raspberrypi:~/ServerSSL $ python RestServerSSL.py
Traceback (most recent call last):
  File "RestServerSSL.py", line 9, in <module>
    from web.wsgiserver import CherryPyWSGIServer
ImportError: No module named wsgiserver 

I had updated the python code to incorporate SSL and suspected I had a different version of web.py on the image to that I was using locally.

I therefore wanted to understand what exactly was installed on the image.

The command below allowed me to startup a container with an interactive bash shell:

docker run -it --entrypoint /bin/bash <ImageName> -s

Then I could run:

pip list 

to list out all the versions of python packages.

It turned out that web.py was at version 0.40 on the image, and 0.38 on my laptop. I upgraded the version on the laptop with:

pip install --upgrade web.py

Then I made the necessary changes (see here for more) and rebuilt the image.
 




Tuesday, 9 July 2019

Docker Volume Control


The Raspberry Pi web.py rest service currently saves files to the folder /home/pi/data on the Docker container. This however is only available for the lifetime of the container. In practice this doesn't matter too much because the service is very stable but when I run updates for example I'd like the current list to persist.

Quick aside: Stopping a running container
(useful if I've left it running for 6 months)

First list the containers with docker ps

pi@raspberrypi:~/Server $ docker ps
CONTAINER ID        IMAGE          ...     NAMES
65cb45e19d62        rest-server    ...     loving_mirzakhani 
 
We are interested in the Names column. In this case run  
docker stop loving_mirzahkani

As per the documentation, volumes are the preferred way to persist data used by containers. So to set this up for the rest server I took the following steps.

Comment out the line to populate the image folder. We don't need to copy anything now so we can remove this line:

COPY data /home/pi/data/

(The data folder originally container start-up data for the webservice)

Then it's simply a case of rebuilding the image and running with this command, using the --mount syntax

docker run -d -p 8080:8080 --mount source=smktdata,target=/home/pi/data rest-server

The first time this was run it automatically created a volume called smktdata

The volume details can be shown with the command

docker volume inspect smktdata

pi@raspberrypi:~/Server $ docker volume inspect smktdata
[
    {
        "CreatedAt": "2019-07-05T18:14:50Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/smktdata/_data",
        "Name": "smktdata",
        "Options": null,
        "Scope": "local"
    }
] 
  
The Mountpoint is the location of the actual data. Files can be viewed with
sudo ls /var/lib/docker/volumns/smktdata/_data

I also have a NAS which is mounted automatically at startup. To use a folder on the NAS, I used this start-up command

docker run -d -p 8080:8080 -v /home/pi/NAS/data:/home/pi/data rest-server

Note that in this case I used the -v (--volume) syntax, this is equivalent to --mount. It essentially just combines all the options into a single field

Tuesday, 18 June 2019

Windows Screensaver Update


My Windows "Random" photos screensaver code hasn't really been significantly touched for many years now, but as it's working really well on a daily basis on my home PCs, I thought I'd add it to GitHub.

You can use this URL to clone: https://github.com/jscott7/PhotosScreensaver.git
(A wiki has also been started: https://github.com/jscott7/PhotosScreensaver/wiki)

As part of the process I performed a bit of a clean up. It's OK, this is a very small project!

First, the settings have an option to change the delay between photos updating, unfortunately while you could change this it wasn't being used.

The settings for the root folder for photos and delay are saved in the registry, I'm using the key HKCU\SOFTWARE\JscoPhotoScreenSaver

public static void SaveSetting(string name, object value)
{
   var key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\JscoPhotoScreenSaver");

   if (value != null)
   {
       key.SetValue(name, value);
   }
}


Then save the photos path to this key with:

SettingsUtilities.SaveSetting("photopath", filePathBox.Text);

To load back use:

object rootPath = SettingsUtilities.LoadSetting("photopath");

There was an inefficiency with the loading of photo files. I was duplicating this for each window. Not a problem for single monitors but it's unnecessary for multiple monitor setups. Fortunately this was easy to fix by moving the logic to the App.xaml.cs file.

Next, to install, the exe built by the project needs to be renamed to PhotosScreensaver.scr. You then right-click on it and select Install. I added a post-build step to the project to automatically perform this rename.

I also made a few tweaks to follow the MS Naming guidelines

Finally, I made use of string interpolation which is new from C# 6. Previously I used a StringBuilder to generate a debug log. This was:

log.Append("Show").Append(window.Width).Append("-").Append(window.Height).Append("-").Append(window.Left).Append("-").AppendLine(window.Top.ToString()); 

And now, with string interpolation it's much cleaner:

log.Append($"Show {window.Width}-{window.Height}-{window.Left}-{window.Top}");