Automatic Scoreboard that Senses Score with Raspberry Pi and Nodejs

Automatic Scoreboard that Senses Score with Raspberry Pi and Nodejs

Automatic Scoreboard that Senses Score with Raspberry Pi and Nodejs.In the end, the basketball hoop score tracking works alright, but could definitely be taken to the next level

On an impulse just before Christmas, I bought myself an NBA “over-the-door” mini basketball hoop. I wasn’t sure what I’d do with it, but having a basketball hoop for my office seemed like a good move. In the end I decided to experiment and bring some connectivity to it by hooking it up to a Raspberry Pi to give it a scoreboard display. Here’s how that went, with step-by-step instructions if you’d like to try to adapt and improve upon it!

This tutorial isn’t intended to be used as a step-by-step “do exactly as I did” style guide — my hope is that you’ll take this concept and use it for all sorts of other ideas. Add a virtual scoreboard that counts how often people come into your office. Or go with a different sport (maybe a mini soccer goal tracker?). Or use an entirely different sensor but track hits on it visually with a Raspberry Pi! There are so many potential applications of this technique. Try stuff and let me know how you go!

What You’ll Need

In order to be able to follow along and make something similar, here’s a list of the parts I used (or their equivalent for the things I had around my lab already):

One thing to note — if you don’t have a 7 inch display for your Pi, you could display the score on a nearby computer monitor too. Any device on your local network with a web browser and a screen would work!

The Code

Want to skip to downloading the code? It’s available on GitHub here.

What I put together

I hung my new basketball hoop up on a door with an ultrasonic sensor attached to the hoop to track when a ball goes into the hoop. Underneath is a Raspberry Pi powered scoreboard — I’d actually recommend finding longer cables so you can connect it outside of basketball falling range.

Me testing out my connected scoreboard — with a customised Suns themed interface!

I’ll go over why everything is as it is below — along with some suggestions for those who might want to improve upon this base!

Languages we’ll be using
  • JavaScript – In order to follow along, you’ll need a knowledge of the basics, but we won’t have lines upon lines of code, things are actually pretty simple in the JS side of things.
  • Node.js – A basic knowledge of how to run npm and Node is needed to run our scoreboard server.
Setting up our Raspberry Pi

If you are completely new to the Raspberry Pi and haven’t set anything up yet, never fear! There are many guides out there for setting things up and it’s nice and straightforward. The Raspberry Pi foundation have a step by step guide for installing the Raspbian operating system using the NOOBS operating system manager. You’ll want to make sure the operating system is running before you get onto any of the other steps.

Touchscreen setup

I put together my connected scoreboard using a Raspberry Pi 3 with touchscreen. My touchscreen and case were already put together and screwed down tight as I’ve used this Pi 3 before for other projects, however if you are starting from scratch — it isn’t too hard to connect up. Newer shipments (like mine) actually have a bunch of it already assembled, with the adapter board already screwed onto the LCD screen, if that’s the case, half the steps are already complete! Instructions on how to assemble the screen are available online:

Case setup

When it comes to putting the case around the LCD screen and Raspberry Pi, that process is also quite easy with the case I have. I already had mine together, however the general steps for this are:

  • Make sure you’ve already got your microUSB card inside the Raspberry Pi and are happy with how it’s running! Annoyingly with a lot of cases, you can’t get the card out once the case is in place. My case linked above is one of those… so make sure the card is all good before you lose access to it!
  • Place the Pi with screen into place inside the case
  • Arrange the ribbon cables and cables coming from the GPIO so they aren’t in the way
  • Make sure the holes for your USB ports and such are on the correct side of the bulkier part of the case and line up nicely.
  • Once everything is lined up nicely, screw in the four screws to put it all together!
  • Turn it on! If you find that the screen comes up upside down, don’t worry, it’s a side effect of the case manufacturers lining up the power to come out of the top. When I mounted my scoreboard though, I mounted it with the power coming out of the bottom, so this wasn’t an issue for me. If it is an issue for you:
    • Run sudo nano /boot/config.txt to open the config for the Pi
    • Then add lcd_rotate=2 to the end, this will rotate the screen around.
    • Press Ctrl X and the Ctrl Y to save your changes.
    • Restart your Pi and when it loads back up it should be the right way around!

Running Node.js on our Raspberry Pi

Conveniently, Raspbian has Node installed by default! However, it is a rather old version of Node. You can check which version is installed on your Pi by opening up the Terminal and typing in:

node -v

I’ve got version 8.15.0 installed on my Pi. You can upgrade by running the following commands:

sudo su - apt-get remove nodered -y apt-get remove nodejs nodejs-legacy -y apt-get remove npm -y curl -sL https://deb.nodesource.com/setup_5.x | sudo bash - apt-get install nodejs -y

After running all of those, if you type in that version command again, you should see a better version:

node -v

You can also check npm is installed correctly by running:

npm -v

With node running on our device, we’re ready to get a scoreboard Node server running!

Our Node.js Scoreboard

The goal with our scoreboard is the following:

  • Set up an ultrasonic sensor watching for movement just within the hoop.
  • Our Node server will watch the distance readings from our ultrasonic sensor.
  • We will run a simple web page that displays the score in reaction to our Node server sensing a point has been made.
  • Send score triggers to our webpage between our Node server and the webpage using WebSockets.

So our Node server’s role will be to run a web server for the scoreboard web page, ping our ultrasonic sensor and send messages to our web page when movement of a ball is spotted.

Here is our final code for those who just want to copy and paste it in to try it out (or to see it as a whole to understand it).

const http = require('http'),
    express = require('express'),
    app = express(),
    server = require('http').Server(app),
    bodyParser = require('body-parser'),
    webpagePort = 8080,
    WebSocketServer = require('ws').Server,
    wss = new WebSocketServer({server: server}),
    Gpio = require('pigpio').Gpio,
    MICROSECONDS_PER_CM = 1e6/34321, // The number of microseconds it takes sound to travel 1cm at 20 degrees celsius
    trigger = new Gpio(23, {mode: Gpio.OUTPUT}),
    echo = new Gpio(24, {mode: Gpio.INPUT, alert: true});

let lastScoreTime = new Date();

app.use(bodyParser.json());

app.use(express.static(__dirname + '/public'));

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Error came ');
});

server.listen(webpagePort, function() {
  console.log('Server is running on ' + webpagePort);
});

wss.on('connection', function connection(ws) {
  console.log('WebSockets are ready!');
});

function broadcast(message) {
  if (message) {
    console.log('Broadcasting ' + message);
    wss.clients.forEach(function each(client) {
      client.send(message);
    });
  }
}

trigger.digitalWrite(0); // Make sure trigger is low

const watchHCSR04 = () => {
  let startTick;

  echo.on('alert', (level, tick) => {
    if (level == 1) {
      startTick = tick;
    } else {
      const endTick = tick;
      const diff = (endTick >> 0) - (startTick >> 0);
      let distance = diff / 2 / MICROSECONDS_PER_CM;
      let currentScoreTime = new Date();
      console.log(distance);
      if (distance  1000)) {
        lastScoreTime = currentScoreTime;
        broadcast('SCORE:' + (diff / 2 / MICROSECONDS_PER_CM));
      }
    }
  });
};

watchHCSR04();

setInterval(() => {
  trigger.trigger(10, 1); // Set trigger high for 10 microseconds
}, 100); // Trigger every 100 milliseconds

We’ll go through each part now and cover what is happening in it.

We start out with a typical set of constants to run a Node Express server. This is a web server that’ll be running on port 8080. Express is a framework for Node.js which we’re using as it makes running a web server nice and simple!

const http = require('http'),
    express = require('express'),
    app = express(),
    server = require('http').Server(app),
    bodyParser = require('body-parser'),
    webpagePort = 8080,

Next, we continue defining constants, however these are for our WebSocket server. WebSockets are how we’ll end messages back and forth between our server and the web page displaying our score. Using WebSockets, we can have that web page open on many monitors and it will update them all. I’m only using the Raspberry Pi screen, but you could go wild and have large monitors around the place to make something pretty extraordinary if you wanted to.

For WebSockets, there are a few different libraries out there, but I like to use ws. It focuses on providing WebSockets in a way that modern browsers can understand natively using the WebSockets standard (so we don’t need to run a JavaScript library on the browser end).

In our code, we define the WebSocketServer object for our server and then make a new WebSocketServer which we allocate to the constant wss.

WebSocketServer = require('ws').Server,
wss = new WebSocketServer({server: server}),

Finally, the last of our constants are all so that we can listen to the readings coming from our ultrasonic sensor. To read data from the ultrasonic sensor, we use the pigpio Node library. This lets us access the GPIO (general-purpose input/output) pins along the top edge of the board — this is where we connect our ultrasonic sensor.

Gpio = require('pigpio').Gpio,

We then add a calculation that is provided from pigpio’s ultrasonic sensor example in their GitHub docs. It calculates how many microseconds it’ll take for sound to travel 1cm at 20 degrees celsius. We’ll use that calculation as the ultrasonic sensor pings sound and then listens for a response — we use the MICROSECONDS_PER_CM to calculate the distance of the response.

MICROSECONDS_PER_CM = 1e6/34321, // The number of microseconds it takes sound to travel 1cm at 20 degrees celsius

Then the final two constants refer to the two GPIO pins we will have our ultrasonic sensors connected to. We will have pin 23 as an output pin called trigger and pin 24 as an input pin called echo.

trigger = new Gpio(23, {mode: Gpio.OUTPUT}),
echo = new Gpio(24, {mode: Gpio.INPUT, alert: true});

The following line allows us to send and interpret JSON strings.

app.use(bodyParser.json());

Then, we set up a few more things for our web server. We first set up where our static HTML/CSS/JS files will be. This is where our Express server will look when we try to access the Raspberry Pi on the port we listed earlier.

app.use(express.static(__dirname + '/public'));

We then set up what should happen when an error occurs, we tell it to log the error to the console and then send a 500 error back.

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Error came ');
});

To run our web server, we call the following code. It’ll show a console message when successfully running.

server.listen(webpagePort, function() {
  console.log('Server is running on ' + webpagePort);
});

After our web server set up, we set up our WebSocket connection. The Node server is our WebSockets server — it will broadcast messages to connected clients (our web browser on the Raspberry Pi). The following code sets up what to do when our WebSocket server is ready. That occurs when the “connection” event occurs. When that happens, we send a console.log, if we don’t see this in the console, we know something has gone wrong on the WebSocket Server end.

wss.on('connection', function connection(ws) {
  console.log('WebSockets are ready!');
});

We follow that with a custom function we create that’ll send out a WebSocket message to any connected clients. Just before it sends that message, it will log a message to show that the message is broadcasting from the server.

function broadcast(message) {
  if (message) {
    console.log('Broadcasting ' + message);
    wss.clients.forEach(function each(client) {
      client.send(message);
    });
  }
}

The code that follows relates to our ultrasonic sensor. This largely comes straight from the pigpio GitHub page example. I did not need to change too much to get it to run nicely for this scenario.

We begin with setting our trigger pin to low (or 0) initially (we will then trigger it to high when we want to time it).

trigger.digitalWrite(0); // Make sure trigger is low

The pigpio library can react to changes in the state of the GPIO pins using something called “alerts”. The pigpio library’s npm page say it tracks these “accurate to a few microseconds” which is enough for us. We set up a function called watchHCSR04 which will keep an eye out for ticks from the GPIO pins and if it receives one, we check how long it stays high (or on), we then work out based on that time and the MICROSECONDS_PER_CM calculation, how many cms away the nearest item was that caused a ping back.

If the distance is less than 11cm, then we trigger a broadcast from our WebSocket Server that’ll let our web browser clients know that movement was spotted. I decided on 11cm after some trial and error, holding the ball at different spots within the hoop while my console.log ran to see what values the ultrasonic sensor reported while the ball was there.

We also check whether the current time against the last time a score was read — if it hasn’t been more than 1000 milliseconds yet, we don’t trigger a new point (e.g. if the ball is rattling around a bit in the hoop, that doesn’t give someone more points!). This was something I added in after spotting a few instances of double counting of points.

const watchHCSR04 = () => {
  let startTick;

  echo.on('alert', (level, tick) => {
    if (level == 1) {
      startTick = tick;
    } else {
      const endTick = tick;
      const diff = (endTick >> 0) - (startTick >> 0);
      let distance = diff / 2 / MICROSECONDS_PER_CM;
      let currentScoreTime = new Date();
      console.log(distance);
      if (distance  1000)) {
        lastScoreTime = currentScoreTime;
        broadcast('SCORE:' + (diff / 2 / MICROSECONDS_PER_CM));
      }
    }
  });
};

watchHCSR04();

In order to actually cause a ping to occur, we need to set our trigger to high (or 1) to give an initial sound from our ultrasonic sensor to measure. In the final bit of our server code, we do that every 100 milliseconds. This is much more frequent than pigpio’s example as I wanted to have more of a chance of spotting movement in the hoop. I adjusted this value lower and lower after a few tests (turns out a basketball can move pretty fast!)

// Trigger a distance measurement once per second
setInterval(() => {
  trigger.trigger(10, 1); // Set trigger high for 10 microseconds
}, 100);

Our Package.json File

We’ll also need our dependencies listed in our package.json file so that we keep track of what our project needs to run! My package.json file looks like so:

{
  "name": "hoopspi",
  "version": "0.0.1",
  "description": "A connected scoreboard for my basketball hoop",
  "main": "index.js",
  "dependencies": {
    "body-parser": "^1.15.2",
    "express": "^4.14.0",
    "gulp": "^3.9.1",
    "pigpio": "^1.2.1",
    "ws": "^1.1.1"
  },
  "devDependencies": {},
  "author": "Patrick Catanzariti",
  "license": "MIT"
}

This contains all of our dependencies used in the Node server above. I’d recommend just copy pasting the above into a new package.json file in the same folder as your index.js file. Once you’ve got that in there, run the following command in your console to install everything needed:

npm install

Our HTML

The HTML is super simple:

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="no index, no follow">
        <title>HoopsPi</title>
        <link href="/css/styles.css" rel="stylesheet" type="text/css">
        <link href="https://fonts.googleapis.com/css?family=ZCOOL+QingKe+HuangYou" rel="stylesheet">
    </head>
    <body>
        <div class="container">
            <div id="score"></div>
        </div>
        <script src="js/scoreboard.js"></script>
    </body>
</html>
Our Front-End JavaScript

Our front-end JavaScript looks like so:

(function() {
    var ws = new WebSocket('ws://192.168.1.133:8080', 'json');
    var score = 0;

    ws.onopen = function () {
        console.log('Websocket is open');
        ws.send('Hi from HoopPi!');
        document.getElementById('score').innerHTML = score;
    };

    ws.onmessage = function (event) {
        if (event.data.indexOf('SCORE:') != -1) {
            score++;
            document.getElementById('score').innerHTML = score;
        }
        console.log('Message was ', event.data);
    };

    ws.onerror = function(error) {
       console.log('Error detected: ' + error.data);
    }
}());

Let’s have a look at what is going on! We start by setting up a WebSocket to watch the IP address our Raspberry Pi is on (use the command ifconfig in the console to find that out). We also set our initial score on page load to 0.

(function() {
    var ws = new WebSocket('ws://192.168.1.133:8080', 'json');
    var score = 0;

After that, we open that WebSocket, send a message to the console and to our WebSocket (that’ll go to the server but we won’t use that message!) and we set our visible score on the web page to our score variable:

ws.onopen = function () {
    console.log('Websocket is open');
    ws.send('Hi from HoopPi!');
    document.getElementById('score').innerHTML = score;
};

When our WebSockets sees a message (this will be the messages from our Pi), we check if it has the contents of "SCORE:" and if so, we increase our score count by one. Technically, in basketball you get two points at least… but I don’t have a way to detect three point shots, so I figured one point was simple enough for now. One day! I also log the data that came through to the browser’s console so we can check it if anything seems wrong.

ws.onmessage = function (event) {
    if (event.data.indexOf('SCORE:') != -1) {
        score++;
        document.getElementById('score').innerHTML = score;
    }
    console.log('Message was ', event.data);
};

Finally, if there are any errors, we log them to the console:

ws.onerror = function(error) {
       console.log('Error detected: ' + error.data);
    }
}());
Wiring Things Up

In order for any of the above to work, we need to have everything all hooked up correctly! The main bit of wiring we’ve got to do is connecting up our ultrasonic sensor to our Raspberry Pi’s GPIO pins we mentioned above.

My GPIO pins looked like so in the end:

Let’s look at exactly what was connected where.

We’ve got to be careful connecting up our ultrasonic sensor. The ultrasonic sensor’s output is 5V, but the Raspberry Pi’s GPIO pins maximum voltage is 3.3V, so we need to include some resistors to make sure we do not damage the GPIO pins. I personally used a 1K and 2K resistor, however the pigpio library’s example uses a 330 and 470 ohm resistor instead (I just didn’t have these around and my resistor alternatives seemed to be okay, I’d recommend following the pigpio recommendation).

When it comes to connecting up the ultrasonic sensor to the breadboard, I connected it using some white jumper cables so that there’d be a bit more length between the breadboard and our Pi. The ultrasonic sensor will be stuck under the hoop, so we need it free from the breadboard to do that! However, before I connected it like that, I connected the ultrasonic sensor directly to the breadboard just to test (it was a lot easier to test the sensor was working while it was propped up in the breadboard, before mounting it to the hoop!).

After adding the jumper cables to it, it looks more like so:

All wiring is shown in the diagram below. We connect up the VCC pin on our ultrasonic sensor to our 5V pin (the one not being used by the LCD screen), the GND pin on our ultrasonic sensor is connected to ground on the Pi, but we also place a 470 ohm resistor between the ground row and the row connected to pin 24 on the Pi. The 330 ohm resistor goes from the row connected to our echo on the ultrasonic sensor to that row connected to pin 24.

When it comes to actually hooking this up to the basketball hoop, I went the route of using picture hanging strips to stick my Raspberry Pi in its case to the wall. In particular, I used Command 5.4kg White Medium Picture Hanging Strips. I took off the removable back of the Pi case and stuck as many as I could to it:

I then reattached that back to the wall, lining up the Pi in its case to ensure it is straight. I stuck mine directly under the hoop — which in retrospect wasn’t the best spot for it. I’d recommend maybe putting it off to the side depending on the length of the jumper cables you’ve got. I gently detached the Pi case from the back once I had it lined up so that I could push down on the back of the case to stick it as firmly to the wall as I could.

I was so worried about whether the Pi would stick that I placed a beanbag underneath the hoop just to be safe! Luckily, after over a week of it hanging there and being hit by a basketball numerous times… it’s still hanging! That tape is magic.

I attached my sensor initially with the same tape onto the hoop, but using tape meant I was limited to somewhere under the hoop that was flat enough to stick it to… this ended up being a bit too low and the basketball net often interferred with tracking. So this is how I’d recommend you not to stick the sensor!

Instead, I took off the sensor from that spot and used blutack to stick it directly under the hoop.

My more successful placement of the ultrasonic sensor!

The net still managed to get in the way, so I used one of the cable ties from the NBA hoop packaging to tie some of the net together to avoid interference:

It’s still not perfect, but seemed to help a little!

I also used one of those cable ties to keep the cables connecting up the ultrasonic sensor together. Those cable ties are super handy.

In Action

To run everything, we need to run the Node.js server using the sudo keyword as our Node app needs solid permissions to be allowed to access the GPIO pins. To run our Node.js server, we enter the following:

sudo node index.js

That should run and look like so in the console:

If we open up our Raspberry Pi’s browser and go to http://localhost:8080 we should see our scoreboard ready to count!

I personally prefer Chromium on my Raspberry Pi as I prefer its full screen mode and more up to date browser. If you don’t have Chromium on your Raspberry Pi, it’s simple to install with two commands:

The usual:

sudo apt-get update

Followed by:

sudo apt-get install chromium-browser --yes

It should then be visible within the “Internet” section of your Pi’s menu:

Where Chromium will be installed

The best part about it all being a web page is that it’s easily customisable! I customised my one to have a Phoenix Suns theme to it:

My Suns themed version of the scoreboard

Conclusion

In the end, the basketball hoop score tracking works alright, but could definitely be taken to the next level. I’m tempted to purchase an IR distance sensor to see whether it tracks more accurately. There’s also a lot more that can be done with the browser-based scoreboard — you could add a countdown timer, or two player mode so you can take turns with a friend!

If you build something similar with my initial concept above, I’d love to hear about what you’ve built! Let me know in the comments below, or get in touch with me on Twitter at @thatpatrickguy.

Raspberry Pi 4 on the Raspberry Pi 4 - Computerphile

Raspberry Pi 4 on the Raspberry Pi 4 - Computerphile

A quick tour of the Raspberry Pi 4 edited on the Raspberry Pi 4. Dr Steve Bagley gets out his knife.dll to unbox Sean's purchases! ☞ [I created a home IoT setup with AWS, Raspberry...

A quick tour of the Raspberry Pi 4 edited on the Raspberry Pi 4. Dr Steve Bagley gets out his knife.dll to unbox Sean's purchases!

I created a home IoT setup with AWS, Raspberry Pi

Benchmarking the Raspberry Pi 4

The easy way to set up Docker on a Raspberry Pi – freeCodeCamp.org

Creating a Rogue Wi-Fi Access Point using a Raspberry Pi

Building a Smart Garden With Raspberry Pi 3B+

Learn Raspberry Pi for Image Processing Applications

Learn Raspberry Pi for Image Processing Applications

New to the newly launched Raspberry Pi 3? Learn all the components of Raspberry Pi, connecting components to Raspberry Pi, installation of NOOBS operating system, basic Linux commands, Python programming and building Image Processing applications on Raspberry Pi. At just $9.

Description
Image Processing Applications on Raspberry Pi is a beginner course on the newly launched Raspberry Pi 3 and is fully compatible with Raspberry Pi 2 and Raspberry Pi Zero.

The course is ideal for those who are new to the Raspberry Pi and want to explore more about it.

You will learn the components of Raspberry Pi, connecting components to Raspberry Pi, installation of NOOBS operating system, basic Linux commands, Python programming and building Image Processing applications on Raspberry Pi.

This course will take beginners without any coding skills to a level where they can write their own programs.

Basics of Python programming language are well covered in the course.

Building Image Processing applications are taught in the simplest manner which is easy to understand.

Users can quickly learn hardware assembly and coding in Python programming for building Image Processing applications. By the end of this course, users will have enough knowledge about Raspberry Pi, its components, basic Python programming, and execution of Image Processing applications in the real time scenario.

The course is taught by an expert team of Electronics and Computer Science engineers, having PhD and Postdoctoral research experience in Image Processing.

Anyone can take this course. No engineering knowledge is expected. Tutor has explained all required engineering concepts in the simplest manner.

The course will enable you to independently build Image Processing applications using Raspberry Pi.

This course is the easiest way to learn and become familiar with the Raspberry Pi platform.

By the end of this course, users will build Image Processing applications which includes scaling and flipping images, varying brightness of images, perform bit-wise operations on images, blurring and sharpening images, thresholding, erosion and dilation, edge detection, image segmentation. User will also be able to build real-world Image Processing applications which includes real-time human face eyes nose detection, detecting cars in video, real-time object detection, human face recognition and many more.

The course provides complete code for all Image Processing applications which are compatible on Raspberry Pi 3/2/Zero.

Who is the target audience?

Anyone who wants to explore Raspberry Pi and interested in building Image Processing applications

To read more:

Raspberry Pi: Dummy tutorial on port forwarding and SSH

Raspberry Pi: Dummy tutorial on port forwarding and SSH

Raspberry Pi: Dummy tutorial on port forwarding and SSH .This is a continuation of my series on setting up Raspberry Pi to be a remote jupyter notebook code editor. In the last chapter Raspberry Pi was set up and could be accessed by SSH at your home network

This is a continuation of my series on setting up Raspberry Pi to be a remote jupyter notebook code editor. In the last chapter Raspberry Pi was set up and could be accessed by SSH at your home network. In this chapter I will guide you how to set up port forwarding and access the Pi remotely from the internet, so you could write command under CLI just like at home.

First time Pi user and first time reader? Check out the first part here.

But once your Pi is accessible from the internet, you need to be 100x cautious about potential security vulnerability. Most of the content you could find on Google Search should guide you to a term “Port Forwarding”, while in the Raspberry Pi official documentation it explicitly told you that port forwarding exposes a known security problem and you should consider altnerative ways to do it. I am going to introduce both ways in this series. And I promise we will get to host website soon, but let’s make sure it’s safe to do so first.

Table of Content
  • Increase your security before exposing your Pi to the internet
  • Port Fowarding
  • What’s next: Cloud Proxy Connections
Increase your security before exposing your Pi to the internet

There are two things you should do before exposing your Pi to the internet.

  1. Change the password of default user Pi

To change the password, simply type in passwd and follow the text instructions by re-typing your old password, your new password and re-tpying your new password.

  1. Create a new user without sudo access and use that user to access your pi remotely

sudo: similar to system admin preveilage in windows, which user can run command that is defined as superuser level, including rebooting your computer and installing any software. You can check out more here.
A good practice, for example, is to use sudo at home to install the software needed and give normal user read/write access to only some sub-folders, then use normal user to remotely login the Pi and only work on these sub-folders.

Let’s create a new user without sudo access, type in sudo adduser normal_user.

You will be asked a series of questions, including the password, basic information of the user and enter Y to confirm all information is correct.

Now we have created a new user normal_user.

To check whether this user have sudo access, we could simply type in sudo -l -U normal_user. And the text should show you ‘User normal_user is not allowed to run sudo on raspberrypi.’

So next time, you could try out SSH connection by not using pi as the login, but normal_user .

Want to know more about user access and organizing user? Check out the tutorial on digitalocean.

Port Forwarding

First, I want to reiterate that setting up port forwarding without any safety add-on to block malicious traffic is not recommended, and this article does not provide enough guidance to set that up. What I would recommend is to set up a cloud proxy server, which we will go through in the next chapter.

With all said, let’s go through a dummy example.

Your home network is known as Private LAN in that no external device could connect to your devices at home. This is controlled by firewall, which by default denies all incoming traffic.

But you don’t always spend your life in Raspberry Pi (me neither, just to be clear), you also love to play Diablo II, a classic rpg game which you could coop with other players. And you play it on another home device, PC. Turns out Diablo II is an old game which requires a direct connection between you and other players in order to hack-and-slash-and-loot the monsters. When you guys are in the game, data package including player’s location, level and action will need to be continuously streamed between players.

Your home PC has an internal IP address of 192.168.1.4. Diablo II automatcially configures a port 1033 for other players to get your data pacakge.

As I mentioned in last chatper, each device at your home will be automatically assigned an IP address by the router (e.g. my Pi’s address is at 192.168.1.50) and each internet application will use up one port number (e.g. 22). A quick refresher example: 192.168.1.50:22 represents <my Raspberry Pi>:<SSH Application>.

Finally, you do a google search and know that your external IP address is 50.247.207.5.

Turns out, if you were able to open a port on the external IP address, and map(point) that port to one set of <Internal IP Address>:<Port>, then you can tell your friends to enter your <External IP Address>:<Port your opened> to route their connection to your <PC's internal IP Address>:<Dialbo II data package application (1033)>.

This is what referred as Port Fowarding and you basically pinhole on your firewall to finally allow incoming traffic to a specific internal IP address and port.

Risk with Port Fowarding

Before I teach you how to forward a port, I want to crystalize what could happen at the worst case.

First, Port Forward won’t expose all your devices at your home. It only allow external user to connect to device you’ve pointed it at. In Diablo II, that’s perfectly fine. As the only application you opened is for other player to receive data package from your game. But for Raspberry Pi, the SSH application represents full access to your Pi’s CLI, and able to run any command including communication with your other home devices. And this is why opening Port for Diablo and XBox are generally safe and trivial but for Raspberry Pi it could be very dangerous.

The chance for any hacker to hide in the brush and wait til you open a port is nearly impossible, let alone to say that hacker needs to know a user / password pair in order to login. So it isn’t really a huge security problem for most of home users. But the possibility is there.

Port Forwarding your Pi to external network

Let’s clarify things we know before we started. From last chatper, we know how to check the internal IP address of our Pi, external IP address of our network and we also know that port 22 is opened for SSH from our Pi.

1~ Enter your router configuration page

Router configuration page is usually a website hosted inside your home network. The url should be printed on the router itself, and definitely shown in the router manual. If you still cannot find it, simply try http://192.168.1.1/ as most of the routers occupied this IP as their configuration page.

2~ Go to port forwarding configuration page

The page location will vary for different brands. Try your best to look for keywords including

  • Advanced Setting, Security Setting, Port Forwading, Virtual Server, Wan Setting

And you should be able to get to the port forwarding page.

3~ Configure rules

For some routers, they will require an extra step to enable port forwarding. Make sure to enable that!

Then, you will probably see a list of inputs, including

  • Service Name: text to describle the port foward service.
  • Source Target [optional]: Whitelist of external IP. Only IPs that are whitelisted could be able to connect to this port. Therefore, if you already know the IP where you are going to make the connection. Adding the whitelist IP here could tremendously increase your security. But this is only available for newer models of router. Leave it blank if you allow all IP to make connection.
  • Port Range: Port that is opened up from your router. In the above example, I open a port on 10300. Let’s say my external IP is 50.247.207.5, using 50.247.207.5:10300 could redirect me to the Pi later.
  • Local IP: IP address of your Pi in your private LAN. Check out last chapter if you don’t know how to find it. In this case it’ 192.168.1.50.
  • Port: Port / Application you want to open from the device specified in the local IP. In this case its 22, since Pi configure port 22 as the SSH application.
  • Protocol: TCP / UDP are usually available. You should also be able to select both. If only one of them can be selected. Please select TCP.

Once you apply the change, you are able to ssh to your Pi anywhere in the world! In this example, we can access our Pi by visiting 50.247.207.5:10300.

Accessing your Pi with windows

Same as last chatper, we could use Putty to connect to our Pi. But this time you could finally try this in a safe network (aka not Starbucks) outside your home wifi.

On Putty, type in your external IP address and Port you open up from the port forwarding setting. In this example it is 50.247.207.5:10300. Keep the connection type as SSH.

And you should be able to login with the CLI pop-up! This time let’s try out our normal_user username and password, so even if hackers get your credential, it’s just a non-sudo user.

And…. we are in! Now you can write and run any program in your Pi from anywhere!

What’s next: Cloud Proxy Connections

Port forwarding is always associated with risk. And we should consider other options like cloud proxy connections. Unfortunately on Raspberry Pi documentation there is no concreted instruction on how to do so, though it does recommend some free services we could use.

In next story, I am going to demonstrate how to use one of the cloud proxy connection service listed in the official documentation to connect to your Pi with SSH, remotely and securely. Stay tuned!