Controlling a WSL installation of redis-server from the Windows command line

If you like using redis for web site caching and you are writing and testing code locally from Windows, you’ll want to figure out how to run a local instance of redis-server. You have a few options. You can run it from another machine that’s running something vaguely Linux-like or MacOS. You can run it from a Docker container under Windows. Or you can run it directly from Windows SubSystem (WSL) for Linux.

For the last few years, Windows (10, 11, Server 2019) comes with a compatibility layer that lets you run Linux binary executables. The current version is WSL 2, but I’m just going to refer to it as WSL.  If you don’t have installed already, just run the following command from an elevated shell (run as administrator)

wsl --install
Installing WSl via command line
Installing WSl via command line

It will install the bits that you need and then ask you to reboot your machine. For more information about installing and configuring WSL, Microsoft has some really good documentation at Install WSL.

The default Linux distribution for WSL is Ubuntu. After you reboot, you may see a Ubuntu shell for a while as Windows installs the bits that you need. It will churn for a bit and then ask you for a username and password. That password will be your sudo (user root) password. One that is done, you should see something like this.

Final step of installing WSL is configuring the default Linux distribution
Final step of installing WSL is configuring the default Linux distribution

The next thing to do is to install redis-server. We can install redis vis apt-get, but before we do that, we need to update apt-get and remove some of the new install shininess off.

sudo apt-get update
sudo apt-get upgrade

After updating apt-get, you’ll want to upgrade it. Confusing? Sort of. Update is updating the instance of apt-get, upgrade is updating all of the packages that were installed via apt-get. After that has finished, you can install redis-server

sudo apt-get install redis-server

There will be some churn and finally, it be installed. Out of the box, redis will not be running. My personal preference is to only run redis when I’m actually using it for development. So I Iike to start and stop it from the command line. Here are commands that you need to know:

sudo service redis-server status
sudo service redis-server start
sudo service redis-server stop

I’ll start up redis with the service start command, and it will come back with a message that redis is starting. And you can use the service status command to verify that it’s running. The acid test is to connect to redis and see if it’s working. You can use the redis-cli tool to set and get a cache value. You should see something like this.

Running redis-cli from the Ubuntu shell
Running redis-cli from the Ubuntu shell

So now redis-server is running. If you close the shell and open up a new one, it will still be running. If you restart WSL or Windows, then it wont be running. Now you can always pop open an Ubuntu shell and start redis-server, but you can do it from a Windows command line

wsl sudo service redis-server status
Running redis commands from PowerShell
Running redis commands from PowerShell

From the screenshot, you can see that WSL passed along the sudo service command to Ubunto. And because I used sudo, I was prompted for the root password. And it returned the same message that I would see from the Ubuntu shell. Since I only have Ubunto installed, that was the default Linux that received the command. If you have multiple distributions installed, you would use “wsl -d DistributionName”. You can get the names of the installed distributions with the “wsl -l” command. Unlike from the Linux shell, each time I invoke “sudo”, I’m prompted for the password. In the Linux shell, you are prompted just the first time you call sudo in a terminal session.

Having to use the root password over and over again can be tedious on a development box. There is a way around that. You can add a file to the /etc/sudoers.d folder in the Linux distribution and remove the root password requirement for the redis-server service. From the Linux shell do the following

cd /etc/sudoers.d
sudo sh
echo "%sudo ALL=(ALL) NOPASSWD: /usr/sbin/service redis-server *" >> allowed-services
sudo chmod 0440 allowed-services
exit

The first thing we do is make /etc/sudoers.d the current folder. Then we use “sudo sh” to gain root access. You need root access to work with this folder. The echo line basically says that you can invoke sudo with no password for redis-server and writes that setting to a file named allowed-services. The file name allowed-services is arbitrary, I picked it because it made sense to me. There is a file in the sudoers.d folder named README, it will explain what the file name restrictions are.

The chmod 0440 command sets the permissions to read-only for the root account and is required for sudoers.d. This allows us to remove the sudo password requirement for redis-server and only for redis-server. Now we can go back to the Windows shell and run the wsl commands without being prompted.

You can even run the redis-cli tool from powershell…

Redis from PowerShell, no password
Redis from PowerShell, no password

The WIndows Subsystem for Linux is one of the hidden gems for developers. And this gem sparkles…

Bonus Round!

Because I’m lazy, I created shortcuts in my PowerShell profile. I added the following functions:

function redstat {wsl sudo service redis-server status}
function redstart {wsl sudo service redis-server start}

And now I can just check the redis-server status via “redstat”

Why I like working on Open Source (back to FocusUF)

About a month ago, I blogged about an update to a webcam hack that I did called FocusUF.  There wasn’t much to the code and I put it all up on GitHub.  Someone came along and submitted a pull request that added some cool functionality.  

My version was hardcoded to a single webcam.  Because that’s all I need it for.  At the time, I was using a Microsoft LifeCam HD-5000.  Someone else created an issue on my GitHub repo asking if I could add support for the HD-6000, which apparently suffers from the same annoyances with focus.

I was going to add a command-line parameter to FocusUF to allow you to specify all or part of the webcam name, but someone else beat me to it.  Cain Hopwood updated my code to add that and a bunch of other useful command-line switches.  And somehow, I had missed his PR when it was submitted a month ago.

So I tossed my changes out the window and accept the pull request.  It was pretty good.  After merging the changes, I added a couple of things.  Cain added code to list all of the webcams.  That would fail if you have any webcams that didn’t support the IAMCameraControl interface from the DirectShowLib.  If you have software that runs as a virtual webcam, it probably doesn’t support IAMCameraControl.   Now when you run it without any parameters, you get the following usage help:

FocusUF 1.2.0.0
Get the source at https://github.com/anotherlab/FocusUF

Usage: FocusUF [--help | -?] [--list-cameras | -l]
[--focus-mode-manual | -fm] [--focus-mode-auto | -fa]
[--set-focus <value> | -f <value>]
[--exposure-mode-manual | -em] [--exposure-mode-auto | -ea]
[--set-exposure <value> | -e <value>]
[--camera-name <name> | -n <name>]

 

Now when you ask it to list the cameras, you get the following output:

❯ .\FocusUF.exe -l
FocusUF 1.2.0.0
Get the source at https://github.com/anotherlab/FocusUF
Camera: c922 Pro Stream Webcam
    Focus Capability: Auto, Manual
    Focus Range: 0 - 250
    Focus Setting: Auto, 0
    Exposure Capability: Auto, Manual
    Exposure Range: -11 - -2
    Exposure Setting: Auto, -5
Camera: XSplit VCam
    Camera does not expose settings through DirectShowLib

I also made the search by name case insensitive.  That was low hanging fruit.  I also updated the compiled version of the code at focusuf.zip.  While I don’t support this as a product, it’s useful for people who don’t have the compiler installed.  And I updated the readme file to document the new changes.

And to go off on a tangent, I’ve been using a tool (Windows only) named Markdown Monster to edit the readme files.  Markdown Monster is written and supported by Rick Strahl.  You can try it for free and then buy a cheap license for it.  Working in Markdown is fairly easy, but it has its own syntax to learn.  Markdown Monster gives you a nice editor with full preview and it makes updating the readme file one less thing to think about.

And that’s one of the great things about open-source software.  Other people can jump in and contribute.  I wrote a little tool to fix something that was bugging me.  It sparked joy with someone and he added some additional joy to fix something that he needed.

Debugging devices without displays or debuggers

I’ve been writing firmware for an RFID reader that connects over USB to an Android device.  Our installers will need to upgrade the readers out in the field and they have no way of knowing which firmware has been installed.  The reader, an Elatec TWN4, has a pretty decent API that you write code for, using the C language.  Their API includes a wonderful function called “Beep”.  You pass in the volume, frequency, how to play the tone (in ms), and finally, how long to be quiet after the tone has been played.  So I have been setting the readers to play a few notes on power up.  This allows the installers to know which firmware has been installed.

The original firmware plays the opening notes to “Smoke On The Water”.  Because anything that can produce at least 4 notes can play it.  The following C code will beep it’s way through some vintage Deep Purple

void Smoke()
{
int v = 50;
int duration = 500;
Beep(v, 2940, duration, 10);
Beep(v, 3490, duration, 10);
Beep(v, 3920, duration * 1.5, 150);
Beep(v, 2940, duration, 10);
Beep(v, 3490, duration, 10);
Beep(v, 4150, duration * 0.5, 10);
Beep(v, 3920, duration * 2, 150);
Beep(v, 2940, duration, 10);
Beep(v, 3490, duration, 10);
Beep(v, 3920, duration * 1.5, 150);
Beep(v, 3490, duration, 10);
Beep(v, 2940, duration * 2.5, 10);
}

We added some code to the firmware to allow our app to put the reader is a sleep mode.  Our installers will need to upgrade a few devices out in the field, so it was time to change that tune.  By checking a few different sites, we found simplified chord progressions for some recognizable songs.  My choices were restricted to simple note changes, you can’t generated complicated chords from a device that only knows how to beep.  It does that beep very well, but at the end of the day it’s only a beep.

I needed to play something else to let the installers know that the firmware had been updated.  Something short, something simple, something simple.  One of my musically inclined co-workers worked out the opening notes of “The Final Countdown” by Europe.  That song has a distinctive opening riff.  And many cover versions.  Some might say too many,

I found a note to frequency conversion table and used that to create a set of constants for the notes I needed.  That allowed me to specify the beeps with readable note constants, instead of the frequency values. You can get those constants here.  With the use of those constants, you can play the opening notes of “The Final Countdown” with the following code:

void FinalCountDown(void)
{
int v = 100;
int duration = 125;
Beep(v, CS5, duration, 10);
Beep(v, B4, duration, 10);
Beep(v, CS5, duration*4, 10);
Beep(v, FS3, duration*5, duration*5);
Beep(v, D5, duration, 10);
Beep(v, CS5, duration, 10);
Beep(v, D5, duration*2, 10);
Beep(v, CS5, duration*2, 10);
Beep(v, B4, duration*3, 10);
}

When using the constants, the code is much easier to read.  And it becomes much easier to create new song intros. With that in place, the installers can quickly check the firmware version by powering up the RFID reader.  At some point I’ll refactor the code to just read the values from an array.  The current design is easy to setup and read, I may just stay with what works.

Right now, I need to use Elatec’s development tools to push the firrmware out via a simple GUI.  If I could get a command line tool for pushing the firmware out, I could add code to the firmware to return the version number from a query sent over USB.  That would allow me to write a simple app or Powershell script to identify a connected reader, query the version, and then push the update out.  If anyone from Elatec ever reads this, a command line firmware updater would be very helpful.

Decades of using development tools like Visual Studio has accustomed me to being able to use a debugger to step through the code.  Writing code where you can’t visually debug it, requires thinking out side the box.  I can test much of the code by having the reader send back text, but when testing with the device that it will be hooked up to, that would interfere with how they work.  Sometimes you just have to use a different path out of the machine to see what it’s doing.