JMRI WebThrottle With Video

Update 8/24/2022: Looks like this will be in JMRI 5.2 more than likely. That will cover the download and installation of the files. There has also been a modification to the webserver so that you can use the camera throttle and the normal WebThrottle without it.

For the last few years SVL has been running hybrid ops where we have remote operators and in layout room operators. The remote operators get a engineers view of the track using our CabCam project. This allows our remote engineers to participate and run through trains or trains with light switching with the help of a local brakeman. We are accomplishing this using modified JMRI WebThrottle code and some fancy memory variables that will be explained below.

Look up Thomas crawling out of his tank engine.

1. Install the WebThrottle JS and CSS files.

Download the webThrottle.css file and the appropriate webThrottle.js file for your install of JMRI. The file labeled webThrottle 426.js is for JMRI versions 4.22-4.26. webThrottle 5+.js is for JMRI 5.0 and up, it works as recently as 5.1.3.

These files will be placed in your JMRI install folder. This is different for various operating systems but you wan to look for /JMRI/web/js and /JMRI/web/css respectively. Place the .js file in the JS folder and rename it webThrottle.js then place the .css file in the CSS folder and rename it webThrottle.css.

On Windows you will want to copy both of these files before you rename them so you can have a backup in the folder. When JMRI gets updated it WILL write over these files with a new version. If you leave a copy in the folder with a different name it can quickly be swapped back in. Linux and MacOS may have the same issue, but I cannot confirm it.

The following setup will be handled in two sections, one for local internal streaming and control, and the next for streaming to remote engineers on the internet. Local streaming is good for testing or if you end up with too many engineers for a room, but not for the layout itself. Internal setup is useful to do before, as much of the setup applies to remote engineers on the internet.

You must also have every engine you want to run with the CabCam added to JMRI’s roster. You can get as fancy or as spartan as you want with this, you can just add NMRA standard CV definitions decoders to your roster, the important bit is the DCC address is in the roster so it shows up in WebThrottle.

2. Internal SetupFirst you are going to need to get the streaming URL for your CabCam which can be obtained from the CabCam setup instructions. Setting the Memory Variables. Open Tools>Tables>Memory Variables.

Where the magic happens.

When this opens click Add… and a window will pop up. In System Name you want to enter IMWTVIDEOURL:XXXX where XXXX is the address of the engine you are wanting to run with the camera. For instance if I had UP 6936 in my roster I would add IMWTVIDEOURL:6936, and if I also wanted to run BNSF 326 I would add IMWTVIDEOURL:326 to the System Name. Don’t enter anything for User Name, hit Create when done. If you have multiple entries to create you can just keep adding DCC addresses without closing that window by just changing the number at the end.

Now you need your CabCam streaming address. If you have a few cameras you can create parking spots for the camera URLS by adding a new variable and naming it IMWTCAMERAURL:# where # is the camera number. Take your streaming URL, it needs to be a IP stream so it needs to end in something like video.mjpeg or stream.h264 etc, so it will look somewhat like this. http://internalcabcamIP:8080/stream/video.mjpeg

Take that address and put it into Value.

If you have not told this to start automatically head to Edit>Preferences>Web Server> and check start automatically. Or you can go to Tools>Servers> Start JMRI Web Server when you want to start it. Now head to your web browser and navigate to the ip and port of your JMRI web server. The URL should look something like http://internalIPofJMRIwebserver:12080/web/webThrottle.html. 12080 is the default port but you can change that in your settings. When you get to the JMRI WebThrottle page click on the engine you assigned a camera too and you should be presented with your throttle and camera.

At this point you can use the throttle internally to your network or setup a VPN on your router to allow friend and family to remotely operate on your layout. The VPN may honestly be the best way for you to do this with friends as it is the most secure way to do this. I won’t go over how to setup a VPN on your router as there are so many different ways to do it. Just Google your router name and VPN and you should find the instructions.

WebThrottle Over the Internet (WOT)

Sometimes there are use cases where you wouldn’t want to setup a VPN and would rather have your remote engineers go to a URL or your DDNS or external IP addresses and use the throttle. This requires more setup on your end and is more unsecure. A good setting for this is if you have less tech savvy remote engineers, or at a club or historical society etc. To start this off you will need to google how to setup port forwarding on your router. I am again going to leave you to handle this as there are so many different routers. Once you are logged into your router you will need to take the IP of your JMRI computer and have the internal port be your JMRI webs servers port, generally 12080 and then set your external port. You can set this to the same port number or you can change the port to something fun like the number of your favorite locomotive, eg 4014 etc. Just make sure to reference the list of port numbers and their uses so you don’t end up using a important port. Ports above 49152 are pretty much fair game.

To connect to your JMRI Webserver from the internet to make sure you did this right you can google “What is my IP” and insert that into this URL http://externalIP:theportyouchose ex and you should see your Server.

Next you want to forward the port for your camera. You will input the IP of the camera, port 8080 for the internal port, and then chose an external port you want to use. If you have multiple cameras chose sequential ports eg. Port 49501 for camera 1, 49502 for camera 2 etc. You can test this by going to the stream of your camera using the external IP eg http://yourexternalIP:49501/stream/video.mjpeg and you should see the stream. That URL you used to see the external stream is what you will put into the memory variable above instead of the internal URL for the locomotive you want to allow be remote operated.

One cool thing you can do with this is setup a CNAME off your website and have people go to a subdomain of your website to run trains. This would end up with a URL like . To do this you will need to log into the DNS section of your domain host. Find the custom records bit and add a CNAME and put whatever you want to come before your websites URL, eg layout, in the hostname bit, leave the TTL, and under data you are either going to put your external IP(this changes so you may need to update this from time to time) or input a URL given to you by a dynamic DNS service like NoIP. These can range from free with some nagging to refresh to a paid service. Many routers have a DDNS service built in but you will need to google how to set that up for your router.

Some words of caution.

One thing to note, anyone with the URL can connect and run a train on your layout while JMRI is running. You can either disable the port forwarding on your router when you are not wanting to allow access, or shut down JMRI. I have not looked into a way to put the webserver behind a login and JMRI does not support secure URLs like HTTPS.

The Future.

There are some features I would like to add is sound, that currently is missing from this project, but UV4L should be able to do it. The WebThrottle code may need a update to support that.

I would also like to roll this all into JMRI releases at some point.

CabCam Goes UV4L

UPDATE 8/27/2022: These instructions have a odd issue with Ubiquiti Unifi wireless AP roaming handoffs. I am currently investigating. If you have a normal Wi-Fi network with only one access point this is not a issue.

This is the updated CabCam software package running UV4L. It operates similarly to MJPEG Streamer but it has a WebGUI for on the fly changes and it generally runs better with less bandwidth useage. If you have already setup the hardware for your CabCam skip to step 3 for the updated software. JMRI’s WebThrottle with video will be the next post.


We describe how to set up a small computer to stream cab view video from an HO locomotive. This allows remote operation of trains at local or remote layouts, optionally connecting it to video conferencing software like Google Meet or Zoom.


  1. Easy to set up and maintain.
  2. Easy to access the cab view via a URL or via conference software eg. Zoom or Meet.
  3. Distribute the setup to others for the betterment of the hobby.
  4. Provide a low latency video stream to enable remote control via Engine Driver/WiThrottle
  5. Keep the hardware within HO NMRA clearances.
  6. Use commonly available components and open-source software where possible.


Hardware: We are using one Raspberry Pi Zero W 2 per CabCam car. The original Zero works as well but is slower.

Camera: The Pi Zero Spy Camera works well for our purposes.

Software: The project uses Raspian Buster running UV4L conference streaming software on the CabCam car. This streams video from a URL on the local network. The video can be viewed locally or streamed to conference software via OBS and the OBS VirtualCam feature. This software runs Raspberry Pi OS Bullseye(Debian 11) 32bit.

Power: The Juiceb0x Zero is a “hat” for the Pi Zero. While the Pi Zero WH comes with the required header already installed, soldering is required to install header pins on the Juiceb0x Zero board.

Rolling Stock: The easiest approach is build a mounting sled out of styrene as shown below. With a little bit more work the setup can be installed inside a dummy engine, too.


How To

This section describes the setup in more detail. Some familiarity with Raspberry Pi and respective software management is helpful.

1. Gathering the hardware

You will need for the self contained unit.

For the cheaper unit running a battery bank:

Raspberry Pi Zero 2 W

Small Battery Power Bank Amazon has some as well.
160 Degree Pi Zero Camera
SDHC card 8GB or larger
USB charger with microUSB charging cable

2. Setting up the hardware

Solder the male header to the Pi Zero 2. Connect the camera to the Pi Zero 2 W. Solder the header pins to the Juiceb0x Zero per the instructions that come with it and attach it to the Pi Zero 2. Connect the battery to the Juiceb0x Zero. Connect the USB charger to the Juiceb0x Zero to charge the battery.

Never connect power to the USB ports of the Pi Zero 2 W while the Juiceb0x Zero is attached. 

For the cheaper version you need plug in the camera then plug the USB micro cable into the power bank and then into Pi Zero. Be mindful of your NMRA gauge, if you need to you can build a sled to hold the Pi Zero on its side so the USB cable is vertical.

3. Burning the image and setting up the software. Those skipping to this step, do this on a second SD card so you don’t mess up your MJPEG Streamer install.

Head over to the Raspberry Pi Foundations website and download the Raspberry Pi Imager and install and run it.

Once open you will be presented with the option to CHOOSE OS, click this and select Raspberry Pi OS(other) and select Raspberry Pi OS Lite(32-bit). Once that is chosen click the gear icon on the main page.

Check Set hostname and set your hostname to whatever you want. I generally chose cabcam# where # is the number of the camera on the layout, eg cabcam1, cabcam2 etc. You want to then mark on the camera hardware which one it is.

Check Enable SSH which automatically checks use password authentication. Below that you can set the username and password. Make sure you write these down or otherwise remember them or you will be making yourself a new image.

Check Configure wireless LAN and set your SSID(Network name) and Password for the wireless network you are going to be using. This MUST be a 2.4ghz network for the Pi Zero W and 2 W. Set your Wireless LAN country to your country abbreviation.

Check Set locale settings and find your time zone. Then if you use a different keyboard layout than US, go ahead and set that.

Optional: Uncheck enable telemetry.

Click SAVE

Click CHOOSE STORAGE and choose your SD card from the options. Then click WRITE. Once the image is written eject your SD card and place it in your Pi. Power the Pi on and give it a few minutes.

4. Logging in to the Pi

Find the IP address your Pi is using via your router and log in using ssh. You may get away with just typing cabcam#.local

Use the credentials you set in step 3.

On a Mac use Terminal. On Windows use PuTTY (you may have to download it)  and put in the IP of your Pi in the Hostname block. Try cabcam.local if you can’t find the IP. When you connect use the credentials you set in step 3.

Windows 1909 and up can use the command prompt with the command shh username@ipadressofpi to connect now so you don’t need putty.

On many networks the following also works:

ssh username@cabcam.local

5. Configuring the Pi

Once on the Pi command line type

sudo rpi-update and update the firmware.

echo /opt/vc/lib/ | sudo tee /etc/

sudo ldconfig

sudo raspi-config

to enter the configuration page for the Pi. Arrow down to 3 Interface Options and open I1 Legacy Camera. Follow the prompts to enable legacy camera drivers so we can use UV4L. Exit the config utility.

6. Install UV4L.

Now we are going to configure the software to allow us to stream the cab POV and you can configure the settings you want.

First run the following command to add the UV4L repo to your install.

curl | sudo apt-key add –

echo “deb stretch main” | sudo tee /etc/apt/sources.list.d/uv4l.listing/uv4l_repo/lpkey

Then run sudo apt-get update, then run sudo apt-get upgrade and accept any prompts.

Run the following accepting any prompts.

sudo apt-get install uv4l uv4l-raspicam

sudo apt-get install uv4l-raspicam-extras

sudo apt-get install uv4l-server

Now you are going to configure UV4L

sudo nano /etc/uv4l/uv4l-raspicam.conf

Set resolution to 640×480 20fps quality to 8(no joke it works great). You can increase this if you are only streaming localy over wifi.
I don’t suggest going much higher if you are going over the internet due to low upload speeds.

You may need to set rotation to flip the camera if your Pi camera is on its side, it goes by degrees so rotation = 180 will flip the image around 180 degrees.

Also find the following and uncomment them.

server-option = –connection-timeout=15

server-option = –enable-keepalive=yes

server-option = –keepalive-timeout=7

and make sure server-option = –max-streams=5 is uncommented and =5. The newer UV4L holds on to connections a little too long.

Run sudo reboot

Now it is time to test the stream.

Open a browser and head to http://IPofPi:8080/

Click MJPEG/Stills Stream and you should see the stream from your camera. If not turn off the Pi and check your cable seating. That is the issue 99% of the time.

The Internet uplink bandwidth at SVL is quite limited. For cab control with remote operators we found that SD resolution is sufficient and limits bandwidth demand. We are using a frame rate of 20 images per second. The stream doesn’t get smoother turning this up.

The camera stream is set to startup on boot.

Put your CabCam car on the front of a train, and run the train while watching the video stream in the browser.

Bernhard wrote down some thoughts on camera placement and car choice on his blog.

9. What’s Next?

To stream the video to remote operators we use OBS with the built in Start Virtual Camera option, configured with CabCam feeds. This is connected to Google Meet and can even stream to Youtube Live. Other video conferencing software like Zoom, Duo, Skype, etc. can be used, too. Remote operators join the video conference and use Engine Driver or WiThrottle to control trains via JMRI over a VPN. You can also run your train all from JMRI’s WebThrottle which will be covered in the next post. OBS will be covered after that because the real star of this show is the WebThrottle.

10. Things to Consider.

If you plan to have multiple cameras you should look into making an image of your SD card so you can burn them to other SD cards without having to do all the above steps. I will leave it up to you to Google “imaging raspberry pi SD card for (insert OS here).” Once you have the image backed up and burned to a new SD card you should run sudo raspi-config and change your hostname to increment your camera name.


Hardware: While we are using a Raspberry Pi Zero 2 W, any Pi with built-in Wifi will work.

Camera: Any compatible Raspberry Pi camera can be made to work. Possible options are the official Pi camera, the spy cameras, or other compatible cameras available from e.g. Adafruit.

Power: The Zero2Go board is an alternative to the Juiceb0xZero. However, the Zero2Go can’t charge the battery. In either case, do not power the Pi from the onboard USB while the power solution board is attached.

Some people had success with using a small form-factor USB power bank connected to a Pi Zero without additional hardware.


Over time we have made corrections to these instructions, or fine tuned settings. Below is a list of important revisions.

  • 8/16/22 Added some information to make the CURL commands work in step 5.

Some sources:

Installation for ARM (Raspberry Pi)