<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.2">Jekyll</generator><link href="https://www.raspberrypi.com/tutorials/feed/" rel="self" type="application/atom+xml" /><link href="https://www.raspberrypi.com/tutorials/" rel="alternate" type="text/html" /><updated>2026-03-09T14:10:04+00:00</updated><id>https://www.raspberrypi.com/tutorials/feed/</id><title type="html">Raspberry Pi tutorials - Raspberry Pi</title><subtitle>From industries large and small, to the kitchen table tinkerer, to the classroom coder, we make computing accessible and affordable for everybody</subtitle><entry><title type="html">How to build a Raspberry Pi cluster</title><link href="https://www.raspberrypi.com/tutorials/cluster-raspberry-pi-tutorial/" rel="alternate" type="text/html" title="How to build a Raspberry Pi cluster" /><published>2024-02-28T00:00:00+00:00</published><updated>2024-02-28T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/cluster-raspberry-pi-tutorial/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/cluster-raspberry-pi-tutorial/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">Now updated for Raspberry Pi OS Bookworm.</div></div>
<p>Why would you build a physical cluster? Today you can go to Amazon, or Digital Ocean, or any of the other cloud providers, and spin up a virtual machine in seconds. But the cloud is just someone else&#8217;s computers: a Raspberry Pi cluster is a low-cost, versatile system you can use for all kinds of clustered-computing related technologies, and you have total control over the machines that constitute it. Building something from the ground up can teach you lessons you can&#8217;t learn elsewhere.</p>
</div>
</div>
<div class="sect1">
<h2 id="what-were-going-to-build">What we&#8217;re going to build</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Bramble-Network-Diagram-v2-800x799.png" alt="Wiring diagram for the cluster"></figure><figcaption><em>Wiring diagram for the cluster</em></figcaption></div>
<p>We&#8217;re going to put together an eight-node cluster connected to a single managed switch. One of the nodes will be the so-called "head" node: this node will have a second Gigabit Ethernet connection out to the LAN/WAN via a USB3 Ethernet dongle, and an external 1TB SSD mounted via a USB3-to-SATA connector. While the head node will boot from an SD card as normal, the other seven nodes — the "compute" nodes — will be configured to network boot, with the head node acting as the boot server and the OS images being stored on the external disk. As well as serving as the network boot volume, the 1TB disk will also host a scratch partition that is shared to all the compute nodes in the cluster.
All eight of our Raspberry Pi boards will have a Raspberry Pi PoE+ HAT attached. This means that, since we&#8217;re using a PoE+ enabled switch, we only need to run a single Ethernet cable to each of our nodes and don&#8217;t need a separate USB hub to power them.</p>
</div>
</div>
<div class="sect1">
<h2 id="what-youll-need">What you&#8217;ll need</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="supplies">Supplies</h3>
<div class="ulist">
<ul>
<li>
<p>8 x Raspberry Pi 4</p>
</li>
<li>
<p>8 x Raspberry Pi PoE+ HAT</p>
</li>
<li>
<p>8-port Gigabit PoE-enabled switch</p>
</li>
<li>
<p>USB 3 to Gigabit Ethernet adaptor</p>
</li>
<li>
<p>USB 3 to SATA adaptor</p>
</li>
<li>
<p>SSD SATA drive</p>
</li>
<li>
<p>8 x Ethernet cables</p>
</li>
<li>
<p>16 GB SD card</p>
</li>
<li>
<p>Cluster case</p>
</li>
</ul>
</div>
<p>The list of parts you&#8217;ll need to put together a Raspberry Pi cluster — sometimes known as a "bramble" — can be short, or it can be quite long, depending on what size and type of cluster you intend to build. So it&#8217;s important to think about what you want the cluster to do before you start ordering the parts to put it together. The list above is what we used for our eight-Pi cluster, but your requirements might well be different.</p>
<p>What you will need is a full bramble of <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi computers</a>, and if you&#8217;re intending to power them over PoE as we are, you&#8217;ll need a corresponding number of <a href="https://www.raspberrypi.com/products/poe-plus-hat/">Raspberry Pi PoE+ HAT</a> boards and an appropriate <a href="https://amzn.to/3D3bzgy">PoE+ switch</a>. Beyond that, however, you&#8217;ll need a micro SD card, some Ethernet cables, a <a href="https://amzn.to/31e6tk3">USB to Ethernet adapter</a>, a <a href="https://amzn.to/3cXOu3Z">USB to SATA adapter cable</a> along with an appropriately sized SSD drive, and some sort of case to put all the components into after you&#8217;ve bought them. The case can either be a custom-designed "cluster case" or, perhaps, something rack-mountable depending on what you&#8217;re thinking of doing with the cluster after you&#8217;ve built it.</p>
<p>There is however a lot of leeway in choosing your components, depending on exactly what you&#8217;re setting up your cluster to do. For instance, depending on the sorts of jobs you&#8217;re anticipating running across the cluster, you might be able to get away with using cheaper 2GB or 1GB boards rather than the 4GB model I used. Alternatively, having a local disk present on each node might be important, so you might need to think about attaching a disk to each board to provide local storage.</p>
<p>However, perhaps the biggest choice when you&#8217;re thinking about building a cluster is how you&#8217;re going to power the nodes. We used PoE for this cluster, which involved adding a <a href="https://www.raspberrypi.com/products/poe-plus-hat/">PoE+ HAT</a> board to each node and purchasing a more expensive switch capable of powering our Raspberry Pi boards: for larger clusters, this is probably the best approach. For smaller clusters, you could instead think about powering the nodes from a USB hub, or for the smallest clusters — perhaps four nodes or fewer — powering each node directly from an individual <a href="https://www.raspberrypi.com/products/type-c-power-supply/">power supply</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="make-your-own-usb-fans">Make your own USB fans</h2>
<div class="sectionbody">
<p>If you decide to power your cluster using PoE, you&#8217;ll find you may have to make up some franken-cables. For instance, the fans at the back of the case I&#8217;m using were intended to connect to the GPIO header block on the Raspberry Pi, but since we&#8217;re using the Raspberry Pi PoE+ HAT to power our nodes, we don&#8217;t have access to the GPIO headers.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_3978-800x600.jpeg" alt="Donor USB cables and a pile of cooling fans"></figure><figcaption><em>Donor USB cables and a pile of cooling fans</em></figcaption></div>
<p>Therefore, for me at least, it&#8217;s time to grab some donor USB cables and make up some cables. If you snip the end from a USB cable and peel back the plastic you&#8217;ll find four wires; these will often be inside an insulating metal sheath. The wires inside the cable are small and delicate, so carefully strip back the cover if present. You&#8217;re looking for the red (+5V) and black (GND) wires. The other two, normally coloured white and green, carry data. You can just cut these data wires off; you won&#8217;t need them.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_3987-800x600.jpeg" alt="Soldering up some franken-cables"></figure><figcaption><em>Soldering up some franken-cables</em></figcaption></div>
<p>Solder the red and black wires from the fan to the red and black wires in the USB cable. The best thing to do here is to use a bit of heat-shrink tubing over each of the individual solder connections, and then use a bigger bit of heat-shrink over both of the soldered connectors. This will give an electrically insulated, and mechanically secure, connection between the fan and the USB plug end of the new cable.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_4026-800x600.jpeg" alt="Four completed Franken-cables"></figure><figcaption><em>Four completed Franken-cables</em></figcaption></div>
<p>The cluster case I&#8217;m using has four fans, mounted at the rear. I&#8217;m going to be powering the left-hand two from the head node, or potentially from the first compute node on the left if I need more USB sockets on the head node, and the right-hand two from the right-most compute node.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_4031-800x600.jpeg" alt="The four rear exhaust fans are mounted in the cluster case"></figure><figcaption><em>The four rear exhaust fans are mounted in the cluster case</em></figcaption></div>
<p>The most common case where you&#8217;ll need Franken-cables is probably this one — powering a fan over USB due to lack of access to the GPIO header. But there are other reasons you might need them. For instance, for a <a href="https://makezine.com/projects/build-a-compact-4-node-raspberry-pi-cluster/">cluster</a> I built a few years back, I needed to put together a cable to power an Ethernet switch from a USB hub, rather than from +5V power supply unit.</p>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS (other) &gt; Raspberry Pi OS Lite</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-cluster</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> (we suggest pi for this tutorial) and password; you’ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
</li>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="building-your-head-node">Building your head node</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_0031-800x600.jpeg" alt="Head node with SSD disk and external Ethernet dongle connected"></figure><figcaption><em>Head node with SSD disk and external Ethernet dongle connected</em></figcaption></div>
<p>The exact way you plug things together is going to depend on your cluster components and whether you picked up a case, or more likely what sort of case you have. I&#8217;m going to slot my head node into the far left-hand side of my case. This lets me mount the SSD drive against one wall of the case using a mounting screw to secure it in place.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_0034-800x600.jpeg" alt="View of the head node from the other side"></figure><figcaption><em>View of the head node from the other side, showing the SSD disk attached to the cluster frame</em></figcaption></div>
<div class="sect2">
<h3 id="connect-over-wireless">Connect over wireless</h3>
<p>We configured the head node to know about our local wireless network during setup, so we should just be able to ssh directly into the head node using the name we gave it during setup:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-cluster.local

&lt;username&gt;@pi-cluster.local's password:
$</code></pre>
</div>
</div>
<p>If we take a look at the network configuration by typing <code>nmcli</code>,</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nmcli
wlan0: connected to preconfigured
        "Broadcom BCM43438 combo and Bluetooth Low Energy"
        wifi (brcmfmac), DC:A6:32:6A:16:91, hw, mtu 1500
        inet4 10.3.194.40/22
        route4 10.3.192.0/22 metric 600
        route4 default via 10.3.194.1 metric 600
        inet6 2001:4d4e:300:c2:1fd1:9c44:f362:3805/64
        inet6 fe80::a725:b6cc:ce19:3caf/64
        route6 fe80::/64 metric 1024
        route6 2001:4d4e:300:c2::/64 metric 600
        route6 default via fe80::dccc:45ff:fe78:a3cc metric 600

lo: connected (externally) to lo
        "lo"
        loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536
        inet4 127.0.0.1/8
        inet6 ::1/128

eth0: disconnected
        "eth0"
        1 connection available
        ethernet (bcmgenet), DC:A6:32:6A:16:90, hw, mtu 1500

DNS configuration:
        servers: 10.3.31.1
        domains: pitowers.org
        interface: eth1

        servers: fe80::8498:d3ff:fe31:8eac
        interface: eth1

        servers: 10.3.194.1
        domains: pitowers.org
        interface: wlan0

        servers: fe80::dccc:45ff:fe78:a3cc
        interface: wlan0

$</code></pre>
</div>
</div>
<p>you can see that <code>wlan0</code> is connected to our local network with a <code>10.3.\*</code> address, while <code>eth0</code> which we&#8217;ve plugged into our switch is disconnected. We&#8217;ll resolve this later in the project by turning our head node into a DHCP server that will assign an IP address to each of the compute nodes, as well as to our smart switch.</p>
</div>
<div class="sect2">
<h3 id="add-a-second-ethernet-connection">Add a second Ethernet connection</h3>
<p>We&#8217;ve been able to reach our head node over the network because we configured our wireless interface <code>wlan0</code> when we set up our SD card. However, it would be good to hardwire our cluster to the network rather than rely on wireless, because we might want to transfer large files back and forth, and wired interfaces are a lot more stable.
To do that we&#8217;re going to need an additional Ethernet connection, so I&#8217;m going to add a <a href="http://amzn.to/31e6tk3">USB 3-to-Gigabit Ethernet</a> adaptor to the head node. We&#8217;ll leave the onboard Ethernet socket (<code>eth0</code>) connected to our PoE switch to serve as the internal connection to the cluster, while we use the second Ethernet connection (<code>eth1</code>) to talk to the outside world.</p>
<p>In most cases <code>eth1</code> will be activated automatically by Network Manager, and pick up an IP address from our LAN&#8217;s DHCP server. After plugging in our adaptor we should see something like this,</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">eth1: connected to Wired connection 2
        "Realtek RTL8153"
        ethernet (r8152), 00:E0:4C:68:1D:DA, hw, mtu 1500
        ip4 default, ip6 default
        inet4 10.3.31.194/24
        route4 10.3.31.0/24 metric 100
        route4 default via 10.3.31.1 metric 100
        inet6 2001:4d4e:300:1f:6f2a:f4b1:65a8:b420/64
        inet6 fe80::7a88:6d47:4554:bd80/64
        route6 fe80::/64 metric 1024
        route6 2001:4d4e:300:1f::/64 metric 100
        route6 default via fe80::8498:d3ff:fe31:8eac metric 100</code></pre>
</div>
</div>
<p>added to the results of typing <code>nmcli</code> on the command line.</p>
<p>We&#8217;ll leave <code>eth0</code>, the onboard Ethernet socket, connected to the Ethernet switch to serve as the internal connection to the cluster. Internally we&#8217;ll allocate <code>192.168.50.*/24</code> addresses to the cluster, with our head node having the IP address <code>192.168.50.1</code>.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nmcli con mod "Wired connection 1" ipv4.addresses 192.168.50.1/24 ipv4.method manual
$ sudo nmcli con down "Wired connection 1"
$ sudo nmcli con up "Wired connection 1"</code></pre>
</div>
</div>
<p>Then, if everything has gone to plan, you should see something like this:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nmcli
eth1: connected to Wired connection 2
        "Realtek RTL8153"
        ethernet (r8152), 00:E0:4C:68:1D:DA, hw, mtu 1500
        ip4 default, ip6 default
        inet4 10.3.31.194/24
        route4 10.3.31.0/24 metric 100
        route4 default via 10.3.31.1 metric 100
        inet6 2001:4d4e:300:1f:6f2a:f4b1:65a8:b420/64
        inet6 fe80::7a88:6d47:4554:bd80/64
        route6 fe80::/64 metric 1024
        route6 2001:4d4e:300:1f::/64 metric 100
        route6 default via fe80::8498:d3ff:fe31:8eac metric 100

wlan0: connected to preconfigured
        "Broadcom BCM43438 combo and Bluetooth Low Energy"
        wifi (brcmfmac), DC:A6:32:6A:16:91, hw, mtu 1500
        inet4 10.3.194.40/22
        route4 10.3.192.0/22 metric 600
        route4 default via 10.3.194.1 metric 600
        inet6 2001:4d4e:300:c2:1fd1:9c44:f362:3805/64
        inet6 fe80::a725:b6cc:ce19:3caf/64
        route6 fe80::/64 metric 1024
        route6 2001:4d4e:300:c2::/64 metric 600
        route6 default via fe80::dccc:45ff:fe78:a3cc metric 600

eth0: connected to Wired connection 1
        "eth0"
        ethernet (bcmgenet), DC:A6:32:6A:16:90, hw, mtu 1500
        inet4 192.168.50.1/24
        route4 192.168.50.0/24 metric 101
        inet6 fe80::a5a8:6819:ddc6:6b2f/64
        route6 fe80::/64 metric 1024

lo: connected (externally) to lo
        "lo"
        loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536
        inet4 127.0.0.1/8
        inet6 ::1/128

DNS configuration:
        servers: 10.3.31.1
        domains: pitowers.org
        interface: eth1

        servers: fe80::8498:d3ff:fe31:8eac
        interface: eth1

        servers: 10.3.194.1
        domains: pitowers.org
        interface: wlan0

        servers: fe80::dccc:45ff:fe78:a3cc
        interface: wlan0

$</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="configure-the-dhcp-server">Configure the DHCP server</h3>
<p>Now we have a "second" Gigabit Ethernet connection out to the world via <code>eth1</code>, and our onboard Ethernet is configured with a static IP address, it&#8217;s time to make our Raspberry Pi into a DHCP server for our cluster on <code>eth0</code>.
Start by installing the DHCP server itself:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install isc-dhcp-server</code></pre>
</div>
</div>
<p>and then edit the <code>/etc/dhcp/dhcpd.conf</code> file as follows:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">ddns-update-style none;
authoritative;
log-facility local7;

# No service will be given on this subnet
subnet 10.3.31.0 netmask 255.255.255.0 {
}

# The internal cluster network
group {
   option broadcast-address 192.168.50.255;
   option routers 192.168.50.1;
   default-lease-time 600;
   max-lease-time 7200;
   option domain-name "cluster";
   option domain-name-servers 8.8.8.8, 8.8.4.4;
   subnet 192.168.50.0 netmask 255.255.255.0 {
      range 192.168.50.20 192.168.50.250;

      # Head Node
      host cluster {
         hardware ethernet dc:a6:32:6a:16:90;
         fixed-address 192.168.50.1;
      }

   }
}</code></pre>
</div>
</div>
<p>Then edit the <code>/etc/default/isc-dhcp-server</code> file to reflect our new server setup:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">DHCPDv4_CONF=/etc/dhcp/dhcpd.conf
DHCPDv4_PID=/var/run/dhcpd.pid
INTERFACESv4="eth0"</code></pre>
</div>
</div>
<p>as well as the <code>/etc/hosts</code> file:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">127.0.0.1	localhost
::1		localhost ip6-localhost ip6-loopback
ff02::1		ip6-allnodes
ff02::2		ip6-allrouters

127.0.1.1	cluster

192.168.50.1	cluster</code></pre>
</div>
</div>
<p>and then you can reboot the head node to start the DHCP service.</p>
<p>We&#8217;ve set things up so that known hosts that aren&#8217;t known are allocated an IP address starting from <code>192.168.50.20</code>. Once we know the MAC addresses of our compute nodes we can add them to the <code>/etc/dhcp/dhcpd.conf</code> file so they grab static IP addresses going forward rather than getting a random one as they come up.
Logging back into your head node after the reboot if you have a managed switch for your cluster, like the <a href="http://amzn.to/3D3bzgy">NETGEAR switch</a> I&#8217;m using which will grab an IP address of its own, you can check your DHCP service is working:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ dhcp-lease-list
Reading leases from /var/lib/dhcp/dhcpd.leases
MAC                IP              hostname       valid until         manufacturer
==================================================================================
80:cc:9c:94:53:35  192.168.50.20   GS308EPP       2021-12-06 14:19:52 NETGEAR
$</code></pre>
</div>
</div>
<p>Otherwise, you&#8217;ll have to wait until you add your first node as unmanaged switches won&#8217;t request their own address.
However, if you do have a managed switch, you might well want to give it a static IP address inside the cluster by adding one to the <code>/etc/dhcp/dhcpd.conf</code> and <code>/etc/hosts</code> files in a similar fashion to the head node. I went with <code>switch</code> as the hostname:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">192.168.50.1	cluster
192.168.50.254	switch</code></pre>
</div>
</div>
<p>and <code>192.168.50.254</code> as the allocated IP address:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">subnet 192.168.50.0 netmask 255.255.255.0 {
   range 192.168.50.20 192.168.50.250;

   # Head Node
   host cluster {
      hardware ethernet dc:a6:32:6a:16:90;
      fixed-address 192.168.50.1;
   }

   # NETGEAR Switch
   host switch {
      hardware ethernet 80:cc:9c:94:53:35;
      fixed-address 192.168.50.254;
   }
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="add-an-external-disk">Add an external disk</h3>
<p>To network boot our compute nodes, we&#8217;re going to need a bit more space. You could do this by plugging a flash stick into one of the USB ports on the head node, but I&#8217;m going to use a <a href="https://amzn.to/3cXOu3Z">USB 3 to SATA Adaptor Cable</a> to attach a 1TB SSD that I had on the shelf in the lab to give the cluster plenty of space for data.
Plugging the disk into one of the USB 3 sockets on the head node I&#8217;m going to format it with a GUID partition table, and a creat single <code>ext4</code> partition on the disk.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo parted -s /dev/sda mklabel gpt
$ sudo parted --a optimal /dev/sda mkpart primary ext4 0% 100%
$ sudo mkfs -t ext4 /dev/sda1
mke2fs 1.46.2 (28-Feb-2021)
Creating filesystem with 244175218 4k blocks and 61046784 inodes
Filesystem UUID: 1a312035-ffdb-4c2b-9149-c975461de8f2
Superblock backups stored on blocks:
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
	4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
	102400000, 214990848

Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done
$</code></pre>
</div>
</div>
<p>We can then mount the disk manually to check everything is okay:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo mkdir /mnt/usb
$ sudo mount /dev/sda1 /mnt/usb
$ sudo systemctl daemon-reload</code></pre>
</div>
</div>
<p>and then make sure it will automatically mount on boot by adding the following to the <code>/etc/fstab</code> file:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">/dev/sda1 /mnt/usb auto defaults,user 0 1</code></pre>
</div>
</div>
<p>You should ensure that you can mount the disk manually before rebooting, as adding it as an entry in the <code>/etc/fstab</code> file might cause the Raspberry Pi to hang during boot if the disk isn&#8217;t available.</p>
</div>
<div class="sect2">
<h3 id="make-the-disk-available-to-the-cluster">Make the disk available to the cluster</h3>
<p>We&#8217;re going to want to make the disk available across the cluster. You&#8217;ll need to install the NFS server software:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install nfs-kernel-server</code></pre>
</div>
</div>
<p>Create a mount point which we can share:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo mkdir /mnt/usb/scratch
$ sudo chown pi:pi /mnt/usb/scratch
$ sudo ln -s /mnt/usb/scratch /scratch</code></pre>
</div>
</div>
<p>Then, edit the <code>/etc/exports</code> file to add a list of IP addresses from which you want to be able to mount your disk:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">/mnt/usb/scratch 192.168.50.0/24(rw,sync)</code></pre>
</div>
</div>
<p>Here we&#8217;re exporting it to <code>192.168.50.0/24</code> which is shorthand for "all the IP addresses between <code>192.168.50.0</code> and `192.168.50.254`".</p>
<p>After doing this you should enable, and then start, both the <code>rpcbind</code> and <code>nfs-server</code> services:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo systemctl enable rpcbind.service
$ sudo systemctl start rpcbind.service
$ sudo systemctl enable nfs-server.service
$ sudo systemctl start nfs-server.service</code></pre>
</div>
</div>
<p>Finally, reboot:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="add-the-first-node">Add the first node</h2>
<div class="sectionbody">
<p>We&#8217;re going to set up our compute node to network boot from our head node. To do that we&#8217;re first going to have to configure our nodes for network boot. How to do this <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#client-configuration">differs between Raspberry Pi models</a>. However, for Raspberry Pi 4 the board must boot a single time from an SD card and the boot order configured using the <code>raspi-config</code> command-line tool.</p>
<div class="sect2">
<h3 id="enable-network-boot">Enable network boot</h3>
<p>The easiest way to proceed is to use the <a href="https://www.raspberrypi.com/software/">Raspberry Pi Imager</a> software to burn a second SD card with Raspberry Pi OS Lite (64-bit). There isn&#8217;t any need to specially configure this installation before booting the board as we did for the head node, except to enable SSH.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">You should not configure or enable the wireless LAN.</div></div>
<p>Next, boot the board attached to the cluster switch:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_0041-800x600.jpg" alt="A second Raspberry Pi 4 powered using PoE+ next to our original head node."></figure><figcaption><em>A second Raspberry Pi 4 powered using PoE+ next to our original head node.</em></figcaption></div>
<p>The board should come up and be visible on the cluster subnet after it gets given an IP address by the head node&#8217;s DHCP server, and we can look at the cluster network from the head node using <code>dhcp-lease-list</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ dhcp-lease-list
Reading leases from /var/lib/dhcp/dhcpd.leases
MAC                IP              hostname       valid until         manufacturer
===============================================================================================
dc:a6:32:6a:16:87  192.168.50.21   raspberrypi    2021-12-07 11:54:29 Raspberry Pi Ltd
$</code></pre>
</div>
</div>
<p>We can now go ahead and SSH into the new board and <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#raspberry-pi-4-model-b">enable network booting</a> using <code>raspi-config</code> from the command line:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh pi@192.168.50.21
$ sudo raspi-config</code></pre>
</div>
</div>
<p>Choose <code>Advanced Options</code> &gt; <code>Boot Order</code> &gt; <code>Network Boot</code>. You&#8217;ll then need to reboot the device for the change to the boot order to be programmed into the bootloader EEPROM.</p>
<p>If you get an error when trying to enable network boot complaining that "No EEPROM bin file found" then you need to update the firmware on your Raspberry Pi before proceeding. Run the following commands:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install rpi-eeprom
$ sudo rpi-eeprom-update -d -a
$ sudo reboot</code></pre>
</div>
</div>
<p>Then, after the node comes back up from its reboot, try to set up network boot once again.</p>
<p>Once the Raspberry Pi has rebooted, check that the boot order using <code>vcgencmd</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ vcgencmd bootloader_config
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0


[all]
BOOT_ORDER=0xf21
$</code></pre>
</div>
</div>
<p>You should now see that <code>BOOT_ORDER</code> is <code>0xf21</code> which indicates that the Raspberry Pi will try to boot from an SD card first followed by the network. Before proceeding any further, we need to take a note of both the Ethernet MAC address and serial number of the Raspberry Pi.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ethtool -P eth0
Permanent address: dc:a6:32:6a:16:87
$ grep Serial /proc/cpuinfo | cut -d ' ' -f 2 | cut -c 9-16
6a5ef8b0
$</code></pre>
</div>
</div>
<p>Afterwards, you can shut down the board, at least for now, and remove the SD card.</p>
<div class="sect3">
<h4 id="set-up-the-head-node-as-a-boot-server">Set up the head node as a boot server</h4>
<p>We now need to configure our head node to act as a boot server. There are several options here, but we&#8217;re going to use our existing DHCP server, along with a standalone TFTP server. You should create a mount point for the server, and install it:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install tftpd-hpa
$ sudo apt install kpartx
$ sudo mkdir /mnt/usb/tftpboot
$ sudo chown tftp:tftp /mnt/usb/tftpboot</code></pre>
</div>
</div>
<p>Edit the <code>/etc/default/tftpd-hpa</code> file:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/mnt/usb/tftpboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure --create"</code></pre>
</div>
</div>
<p>Then, restart the service:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo systemctl restart tftpd-hpa</code></pre>
</div>
</div>
<p>We then need to set up our boot image, and we&#8217;re going to need to create one image per client. The first step is to grab the latest image from the web and mount it so we can make some changes, and then mount the partitions inside the image so we can copy the contents to our external disk:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo su
# mkdir /tmp/image
# cd /tmp/image
# wget -O raspios_lite_latest.img.xz https://downloads.raspberrypi.com/raspios_lite_arm64_latest
# xz -d raspios_lite_latest.img.xz
# kpartx -a -v *.img
# mkdir bootmnt
# mkdir rootmnt
# mount /dev/mapper/loop0p1 bootmnt/
# mount /dev/mapper/loop0p2 rootmnt/
# mkdir -p /mnt/usb/rpi1
# mkdir -p /mnt/usb/tftpboot/6a5ef8b0
# cp -a rootmnt/* /mnt/usb/rpi1
# cp -a bootmnt/* /mnt/usb/rpi1/boot/firmware</code></pre>
</div>
</div>
<p>Where "6a5ef8b0" is the serial number of your first node which we retrieved earlier.</p>
<p>Afterwards, we can customise the root file system:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session"># touch /mnt/usb/rpi1/boot/firmware/ssh
# echo pi:$(echo 'raspberry' | openssl passwd -6 -stdin) &gt; /mnt/usb/rpi1/boot/firmware/userconf.txt
# sed -i /UUID/d /mnt/usb/rpi1/etc/fstab
# echo "192.168.50.1:/mnt/usb/tftpboot/6a5ef8b0 /boot/firmware nfs defaults,vers=3 0 0" &gt;&gt; /mnt/usb/rpi1/etc/fstab
# echo "console=serial0,115200 console=tty root=/dev/nfs nfsroot=192.168.50.1:/mnt/usb/rpi1,vers=3 rw ip=dhcp rootwait" &gt; /mnt/usb/rpi1/boot/firmware/cmdline.txt</code></pre>
</div>
</div>
<p>and then add it to the <code>/etc/exports</code> files on the head node:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session"># echo "/mnt/usb/rpi1 192.168.50.0/24(rw,sync,no_subtree_check,no_root_squash)" &gt;&gt; /etc/exports</code></pre>
</div>
</div>
<p>And then clean up after ourselves:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session"># systemctl restart rpcbind
# systemctl restart nfs-server
# umount bootmnt/
# umount rootmnt/
# cd /tmp; rm -rf image
# exit
$</code></pre>
</div>
</div>
<p>Finally, we need to edit the <code>/etc/dhcp/dhcpd.conf</code> file as follows:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">ddns-update-style none;
authoritative;
log-facility local7;
option option-43 code 43 = text;
option option-66 code 66 = text;

# No service will be given on this subnet
subnet 10.3.31.0 netmask 255.255.255.0 {
}

# The internal cluster network
group {
   option broadcast-address 192.168.50.255;
   option routers 192.168.50.1;
   default-lease-time 600;
   max-lease-time 7200;
   option domain-name "cluster";
   option domain-name-servers 8.8.8.8, 8.8.4.4;
   subnet 192.168.50.0 netmask 255.255.255.0 {
      range 192.168.50.20 192.168.50.250;

      # Head Node
      host cluster {
         hardware ethernet dc:a6:32:6a:16:90;
         fixed-address 192.168.50.1;
      }

      # NETGEAR Switch
      host switch {
         hardware ethernet 80:cc:9c:94:53:35;
         fixed-address 192.168.50.254;
      }

      host rpi1 {
         option root-path "/mnt/usb/tftpboot/";
         hardware ethernet dc:a6:32:6a:16:87;
         option option-43 "Raspberry Pi Boot";
         option option-66 "192.168.50.1";
         next-server 192.168.50.1;
         fixed-address 192.168.50.11;
         option host-name "rpi1";
      }

   }
}</code></pre>
</div>
</div>
<p>and reboot our Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="network-boot-our-node">Network boot our node</h3>
<p>Make sure you&#8217;ve removed the SD card from the compute node, and plug the Raspberry Pi back into your switch. If you&#8217;ve got a spare monitor handy it might be a good idea to plug it into the HDMI port so you can watch the diagnostics screen as the node boots.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_0051-800x600.jpg" alt="Network booting our first compute node for the first time. It's connected to a display for debugging."></figure><figcaption><em>Network booting our first compute node for the first time. It&#8217;s connected to a display for debugging.</em></figcaption></div>
<p>If all goes to plan the board should boot up without incident. Although there are a few things we will need to tidy up, you should now be able to SSH directly into the compute node.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh pi@192.168.50.11

pi@192.168.50.11's password:
$</code></pre>
</div>
</div>
<p>If you were watching the boot messages on a monitor, or if you check in the logs, you can see that our image didn&#8217;t come up entirely cleanly. If you log back into the compute node you can make sure that doesn&#8217;t happen in future by turning off the feature where the Raspberry Pi tries to resize its filesystem on the first boot, and also by uninstalling the swap daemon.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo systemctl disable resize2fs_once.service
$ sudo systemctl disable sshswitch.service
$ sudo apt remove dphys-swapfile</code></pre>
</div>
</div>
<p>Next, we should change the hostname from the default <code>raspberrypi</code> to <code>rpi1</code> using the <code>raspi-config</code> command-line tool:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo raspi-config</code></pre>
</div>
</div>
<p>Select <code>System Options</code> &gt; <code>Hostname</code> to change the hostname of the compute node, and select "Yes" to reboot.</p>
<p>Finally, we can make things slightly easier on ourselves, so that we don&#8217;t have to use the IP address of our compute and head nodes every time, by adding our current and future compute nodes to the <code>/etc/hosts</code> file on both our head and compute nodes:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">127.0.0.1	localhost
::1		localhost ip6-localhost ip6-loopback
ff02::1		ip6-allnodes
ff02::2		ip6-allrouters

127.0.1.1	cluster

192.168.50.1	cluster
192.168.50.254	switch

192.168.50.11	rpi1
192.168.50.12	rpi2
192.168.50.13	rpi3
192.168.50.14	rpi4
192.168.50.15	rpi5
192.168.50.16	rpi6
192.168.50.17	rpi7</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="mount-the-scratch-disk">Mount the scratch disk</h3>
<p>Normally if we were mounting a network disk we&#8217;d make use <code>autofs</code> rather than adding it as an entry directly into the <code>/etc/fstab</code> file. However here, with our entire root filesystem mounted via the network, that seems like unnecessary effort.
After it reboots log back into your compute node, add a mount point:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo mkdir /scratch
$ sudo chown pi:pi scratch</code></pre>
</div>
</div>
<p>Edit the <code>/etc/fstab</code> file there to add the scratch disk:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">192.168.50.1:/mnt/usb/scratch /scratch nfs defaults 0 0</code></pre>
</div>
</div>
<p>Then, reboot the compute node:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="secure-shell-without-a-password">Secure shell without a password</h3>
<p>It&#8217;s going to get pretty tiresome secure-shelling between the cluster head node and the compute nodes and having to type your password each time. So let&#8217;s enable secure shell without a password by generating a public/private key pair.
On the compute node you should edit the <code>/etc/ssh/sshd_config</code> file to enable public key login:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">PubkeyAuthentication yes
PasswordAuthentication yes
PermitEmptyPasswords no</code></pre>
</div>
</div>
<p>and then restart the <code>sshd</code> server:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo systemctl restart ssh</code></pre>
</div>
</div>
<p>Then going back to the head node we need to generate our public/private key pair and distribute the public key to the compute node. Use a blank passphrase when asked.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh-keygen -t rsa -b 4096 -C "pi@cluster"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/pi/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/pi/.ssh/id_rsa
Your public key has been saved in /home/pi/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:XdaHog/sAf1QbFiZj7sS9kkFhCJU9tLN0yt8OvZ52gA pi@cluster
The key's randomart image is:
+---
[RSA 4096]----+
|     ...o  *+o   |
|      ...+o+*o . |
|       .o.=.B++ .|
|         = B.ooo |
|        S * Eoo  |
|         .o+o=   |
|         ..+=o.  |
|          ..+o +.|
|           .  +o.|
+----
[SHA256]-----+
$ ssh-copy-id -i /home/pi/.ssh/id_rsa.pub pi@rpi1
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/pi/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
pi@rpi1's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'pi@rpi1'"
and check to make sure that only the key(s) you wanted were added.
$</code></pre>
</div>
</div>
<p>Afterwards, you should be able to login to the compute node without having to type your password.</p>
</div>
<div class="sect2">
<h3 id="access-to-the-outside-world">Access to the outside world</h3>
<p>One thing our compute node doesn&#8217;t have right now is access to the LAN. Right now the compute node can only see the head node and eventually, once we add them, the rest of the compute nodes. But we can fix that! On the head node go and edit the <code>/etc/sysctl.conf</code> file by uncommenting the following line:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">net.ipv4.ip_forward=1</code></pre>
</div>
</div>
<p>After activating forwarding we&#8217;ll need to configure <code>iptables</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install iptables
$ sudo iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
$ sudo iptables -A FORWARD -i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
$ sudo iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT
$ sudo sh -c "iptables-save &gt; /etc/iptables.ipv4.nat"</code></pre>
</div>
</div>
<p>and then add a line — just above the <code>exit 0</code> line — in the <code>/etc/rc.local</code> file a line to load the tables on boot:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">_IP=$(hostname -I) || true
if
[ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

iptables-restore &lt; /etc/iptables.ipv4.nat

exit 0</code></pre>
</div>
</div>
<p>and reboot:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">If you still have the compute node running, you should log on to that first and shut it down, as the root filesystem for that lives on a disk attached to our head node.</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="add-the-next-compute-node">Add the next compute node</h2>
<div class="sectionbody">
<p>Adding the rest of the compute nodes is going to be much more straightforward than adding our first node as we can now use our customised image and avoid some of the heavy lifting we did for the first compute node.</p>
<p>Go ahead and grab your SD card again and boot your next Raspberry Pi attached to the cluster switch.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_0059-800x600.jpg" alt="Booting the second compute node."></figure><figcaption><em>Booting the second compute node.</em></figcaption></div>
<p>The board should come up and be visible on the cluster subnet after it gets given an IP address by the head node&#8217;s DHCP server, and we can look at the cluster network from the head node using <code>dhcp-lease-list</code>.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ dhcp-lease-list
Reading leases from /var/lib/dhcp/dhcpd.leases
MAC                IP              hostname       valid until         manufacturer
===============================================================================================
dc:a6:32:6a:15:e2  192.168.50.21   raspberrypi    2021-12-08 21:15:00 Raspberry Pi Ltd
$</code></pre>
</div>
</div>
<p>We can now go ahead and SSH into the new board and again <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#raspberry-pi-4-model-b">enable network booting</a> for this board using <code>raspi-config</code> from the command line:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ rm /home/pi/.ssh/known_hosts
$ ssh &lt;username&gt;@129.168.50.21
$ sudo raspi-config</code></pre>
</div>
</div>
<p>Choose <code>Advanced Options</code> &gt; <code>Boot Order</code> &gt; <code>Network Boot</code>. You&#8217;ll then need to reboot the device for the change to the boot order to be programmed into the bootloader EEPROM.
Once the Raspberry Pi has rebooted, check the boot order using <code>vcgencmd</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ vcgencmd bootloader_config
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0


[all]
BOOT_ORDER=0xf21
$</code></pre>
</div>
</div>
<p>which should now show that the <code>BOOT_ORDER</code> is <code>0xf21</code> which indicates that the Raspberry Pi will try to boot from an SD card first followed by the network. Before proceeding any further, we need to take a note of both the Ethernet MAC address and serial number of the Raspberry Pi.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ethtool -P eth0
Permanent address: dc:a6:32:6a:15:e2
$ grep Serial /proc/cpuinfo | cut -d ' ' -f 2 | cut -c 9-16
54e91338
$</code></pre>
</div>
</div>
<p>Afterwards, you can shut down the board, at least for now, and remove the SD card.</p>
<p>Moving back to our head node we can use our already configured image as the basis of the operating system for the next compute node.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo su
$ mkdir -p /mnt/usb/rpi2
$ cp -a /mnt/usb/rpi1/* /mnt/usb/rpi2
$ mkdir -p /mnt/usb/tftpboot/54e91338
$ echo "/mnt/usb/rpi2/boot/firmware /mnt/usb/tftpboot/54e91338 none defaults,bind 0 0" &gt;&gt; /etc/fstab
$ echo "/mnt/usb/rpi2 192.168.50.0/24(rw,sync,no_subtree_check,no_root_squash)" &gt;&gt; /etc/exports
$ exit
$</code></pre>
</div>
</div>
<p>Then we need to edit the <code>/mnt/usb/rpi2/boot/firmware/cmdline.txt</code>, replacing <code>rpi1</code> with <code>rpi2</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">console=serial0,115200 console=tty root=/dev/nfs nfsroot=192.168.50.1:/mnt/usb/rpi2,vers=3 rw ip=dhcp rootwait</code></pre>
</div>
</div>
<p>and similarly for <code>/mnt/usb/rpi2/etc/hostname</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">rpi2</code></pre>
</div>
</div>
<p>Finally, edit the <code>/etc/dhcp/dhcpd.conf</code> file on the head node:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-clike" data-lang="clike">host rpi2 {
   option root-path "/mnt/usb/tftpboot/";
   hardware ethernet dc:a6:32:6a:15:e2;
   option option-43 "Raspberry Pi Boot";
   option option-66 "192.168.50.1";
   next-server 192.168.50.1;
   fixed-address 192.168.50.12;
   option host-name "rpi2";
}</code></pre>
</div>
</div>
<p>and reboot our head node:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Afterwards, you should see both <code>rpi1</code> and <code>rpi2</code> are up and running. If you&#8217;re interested, we can get a better look at our cluster network by installing <code>nmap</code> on the head node:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install nmap
$ nmap 192.168.50.0/24
Starting Nmap 7.80 ( https://nmap.org ) at 2021-12-09 11:40 GMT
Nmap scan report for cluster (192.168.50.1)
Host is up (0.0018s latency).
Not shown: 997 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
111/tcp  open  rpcbind
2049/tcp open  nfs

Nmap scan report for rpi1 (192.168.50.11)
Host is up (0.0017s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE
22/tcp open  ssh

Nmap scan report for rpi2 (192.168.50.12)
Host is up (0.00047s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE
22/tcp open  ssh

Nmap scan report for switch (192.168.50.254)
Host is up (0.014s latency).
Not shown: 999 filtered ports
PORT   STATE SERVICE
80/tcp open  http

Nmap done: 256 IP addresses (4 hosts up) scanned in 6.91 seconds
$</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="add-the-rest-of-the-nodes">Add the rest of the nodes</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Mi9VPcXiR4OfoVSu6iNkWQ_thumb_10c70-800x600.jpg" alt="The final Bramble"></figure><figcaption><em>The final Bramble</em></figcaption></div>
<p>Adding the remaining five compute nodes is now more or less a mechanical process. You&#8217;ll need to follow the process we went through for <code>rpi2</code> for <code>rpi3</code>, <code>rpi4</code>, <code>rpi5</code>, <code>rpi6</code>, and <code>rpi7</code>. Substituting the appropriate MAC address, serial number, and hostname for each of the new compute nodes:</p>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Hostname</th>
<th class="tableblock halign-left valign-top">MAC Address</th>
<th class="tableblock halign-left valign-top">Serial Number</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">rpi1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">dc:a6:32:6a:16:87</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">6a5ef8b0</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">rpi2</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">dc:a6:32:6a:15:e2</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">54e91338</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">rpi3</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">dc:a6:32:6a:15:16</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">6124b5e4</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">rpi4</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">dc:a6:32:6a:15:55</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">52cddb85</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">rpi5</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">dc:a6:32:6a:16:1b</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">a0f55410</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">rpi6</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">dc:a6:32:6a:15:bb</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">c5fb02d3</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">rpi7</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">dc:a6:32:6a:15:4f</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">f57fbb98</p></td>
</tr>
</tbody>
</table>
<p>When bringing the last compute node up I also went ahead and plugged the two remaining franken-cables into the final node to power the right-most fans in my case.</p>
</div>
</div>
<div class="sect1">
<h2 id="control-your-raspberry-pi-cluster">Control your Raspberry Pi cluster</h2>
<div class="sectionbody">
<p>Now we have all our nodes up and running, we need some cluster control tools. One of my favourites is the <code>parallel-ssh</code> toolkit. You can install this on the head node from the command line:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ apt install pssh</code></pre>
</div>
</div>
<p>and, along with the excellent <a href="https://github.com/ParallelSSH/parallel-ssh">ParallelSSH Python library</a> allowing you to build your own cluster automation, this will install a number of command-line tools; <code>parallel-ssh</code>, <code>parallel-scp</code>, <code>parallel-rsync</code>, <code>parallel-slurp</code>, and <code>parallel-nuke</code>. These tools can help you run and control jobs, and move and copy files, between the head node and the compute nodes.
To use the command line tools you&#8217;ll need to create a hosts file listing all the compute nodes, I saved mine as <code>.pssh_hosts</code> in my home directory:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ cat .pssh_hosts
rpi1
rpi2
rpi3
rpi4
rpi5
rpi6
rpi7
$</code></pre>
</div>
</div>
<p>After creating the file we can use the command line tools to, amongst other things, execute a command on all seven of our compute nodes.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ parallel-ssh -i -h .pssh_hosts free -h
[1] 12:10:15 [SUCCESS] rpi4
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi        56Mi       3.7Gi       8.0Mi        64Mi       3.7Gi
Swap:            0B          0B          0B
[2] 12:10:15 [SUCCESS] rpi1
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi        55Mi       3.7Gi       8.0Mi        64Mi       3.7Gi
Swap:            0B          0B          0B
[3] 12:10:15 [SUCCESS] rpi2
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi        55Mi       3.7Gi       8.0Mi        64Mi       3.7Gi
Swap:            0B          0B          0B
[4] 12:10:15 [SUCCESS] rpi7
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi        56Mi       3.7Gi       8.0Mi        97Mi       3.6Gi
Swap:            0B          0B          0B
[5] 12:10:15 [SUCCESS] rpi3
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi        55Mi       3.7Gi        16Mi       104Mi       3.6Gi
Swap:            0B          0B          0B
[6] 12:10:15 [SUCCESS] rpi5
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi        55Mi       3.7Gi        16Mi        72Mi       3.6Gi
Swap:            0B          0B          0B
[7] 12:10:15 [SUCCESS] rpi6
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi        55Mi       3.7Gi       8.0Mi        64Mi       3.7Gi
Swap:            0B          0B          0B
$</code></pre>
</div>
</div>
<p>Although you should take note that the results will come back in a random order depending on how quickly the command was executed on each of the compute nodes.</p>
<div class="sect2">
<h3 id="add-a-remote-shutdown-service">Add a remote shutdown service</h3>
<p>While <code>parallel-ssh</code> is a great tool to allow you to deploy software and do other tasks across your cluster, sometimes you just want to shut the cluster down cleanly with a single command. There are a bunch of ways you can approach this, the simplest is just to write a shell script to login to each of the compute nodes and shut them down before shutting down the head node itself. Alternatively, you could deploy something like the <a href="https://github.com/spujadas/rshutdown"><code>rshutdown</code> service</a>, editing <a href="https://github.com/spujadas/rshutdown/blob/4ea293c6264c324324f0ce90ca02612305d6390a/src/main.c#L72">the command</a> appropriately.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="take-your-raspberry-pi-cluster-further">Take your Raspberry Pi cluster further</h2>
<div class="sectionbody">
<p>Up until this point, the cluster we&#8217;ve built is pretty flexible, and now we have a firm base we can start installing software depending on exactly what we&#8217;re looking to do with our cluster. For instance, if we&#8217;re building a compute cluster for modelling, we&#8217;d probably look to <a href="https://www.anthonymorast.com/blog/2019/10/31/setting-up-a-raspberry-pi-cluster-to-use-mpi/">install MPI</a> and OpenMP to do parallel processing across our cluster. Alternatively, you might be looking to build out a <a href="https://ubuntu.com/tutorials/how-to-kubernetes-cluster-on-raspberry-pi#4-installing-microk8s">cluster to host Kubernetes</a>.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[A Raspberry Pi cluster is a low-cost, versatile system you can use for all kinds of clustered-computing related technologies, and you have total control over the machines that constitute it.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/Cluster-800x533.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/Cluster-800x533.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Host a Wi-Fi hotspot with a Raspberry Pi</title><link href="https://www.raspberrypi.com/tutorials/host-a-hotel-wifi-hotspot/" rel="alternate" type="text/html" title="Host a Wi-Fi hotspot with a Raspberry Pi" /><published>2023-12-15T00:00:00+00:00</published><updated>2023-12-15T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/host-a-hotel-wifi-hotspot/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/host-a-hotel-wifi-hotspot/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Dealing with hotel Wi-Fi is almost always a pain. Signing into a portal that doesn&#8217;t always work properly on every device&#8201;&#8212;&#8201;your phone, laptop, tablet, e-reader, watch, and more&#8201;&#8212;&#8201;is error-prone, and it&#8217;s an easy way to end up accidentally adding pricey internet fees to your hotel stay. Some hotel Wi-Fi only allows a single device per room! Most won&#8217;t let your devices communicate with each other, and if they do, they may well present a security risk.</p>
<p>You can use a Raspberry Pi to connect to hotel Wi-Fi once, then broadcast a separate network to all of your devices. With this setup, you won&#8217;t have to configure Wi-Fi for all of your devices every time you visit a hotel. Instead, you can set them up once, and then every time you go to a hotel, your devices will automatically connect to the Raspberry Pi&#8217;s network.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">This tutorial describes hosting a hotspot from a hotel Wi-Fi network connection, but the same procedure should work for any public Wi-Fi network that uses a captive portal, including guest networks at airports, college campuses, and coffee shops.</div></div>
<p>We&#8217;ll begin by setting up the hotspot at home. To use the hotspot once you&#8217;re actually at a hotel, see <a href="#use-the-hotspot">Use the hotspot</a>.</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>Suitable Raspberry Pi power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the power supply documentation for details</a>)</p>
</li>
<li>
<p>MicroSD card (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">the SD card documentation for details</a>)</p>
</li>
<li>
<p>Adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>USB Wi-Fi adapter</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up as NAS.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi">Choose the right Raspberry Pi</h3>
<p>The faster your Raspberry Pi, the better performance you&#8217;ll get. For this tutorial, we&#8217;ll be using a <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi 4 2GB</a>.</p>
<p>It&#8217;s a good idea to choose a Raspberry Pi with a built-in Wi-Fi module, because you&#8217;ll need <em>two</em> Wi-Fi devices to host your own hotel Wi-Fi hotspot: one to connect to the hotel network, and one to broadcast a network to your other devices.</p>
</div>
<div class="sect2">
<h3 id="choose-the-right-usb-wi-fi-adapter">Choose the right USB Wi-Fi adapter</h3>
<p>Most USB Wi-Fi adapters with Linux driver support should suffice.</p>
<p>For this tutorial, we used a <a href="https://thepihut.com/products/usb-wifi-adapter-for-the-raspberry-pi">802.11 b/g/n 2.4GHz adapter</a> built around the MediaTek MT7601U chipset.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images//hotspot/adapter.jpg" alt="AUSB WiFi (802.11 b/g/n) 2.4GHz adapter for Raspberry Pi"></figure></div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">If you chose a Raspberry Pi that doesn&#8217;t include a built-in Wi-Fi module, you will need <strong>two</strong> USB Wi-Fi adapters. At least one of your Wi-Fi adapters must support AP (Access Point) mode to broadcast a hotspot network.</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS Lite (32-bit)</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-hotspot</code> for this tutorial).</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate.</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi.</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router.</p>
</li>
</ul>
</div>
</li>
<li>
<p>In the Services tab, check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard.</p>
<div class="ulist">
<ul>
<li>
<p>Enable <strong>password authentication</strong> for SSH connections.</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="set-up-your-raspberry-pi">Set up your Raspberry Pi</h2>
<div class="sectionbody">
<p>Power down your Raspberry Pi by disconnecting it from the power supply. Then, attach your USB WiFi adapter (or adapters) to your Raspberry Pi. Finally, power your Raspberry Pi by plugging it back into the power supply.</p>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to remotely connect to your Raspberry Pi, eliminating the need for a keyboard and mouse. It&#8217;s perfect if your Raspberry Pi is located in a hard-to-reach location like the back of your display.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the hostname you set using Raspberry Pi Imager. If you have issues connecting using this method, you may want to use your Raspberry Pi&#8217;s IP address instead. For more information about finding your IP address and accessing your Raspberry Pi remotely, see <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">the remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-via-ssh">Connect via SSH</h3>
<p>Open a terminal session on <em>your usual computer</em>. To access your Raspberry Pi via SSH, run the following command, replacing <code>&lt;username&gt;</code> with the user name you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-hotspot.local</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-hotspot.local
The authenticity of host 'pi-hotspot.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-hotspot.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-hotspot.local's password:
Linux pi-hotspot 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Oct 24 09:41:00 2023
&lt;username&gt;@pi-hotspot:~ $</code></pre>
</div>
</div>
<p>When asked for your password, use the password you created in Raspberry Pi Imager.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-hotspot">Configure hotspot</h2>
<div class="sectionbody">
<p>Now that your Raspberry Pi is up and running, it&#8217;s time to transform it into a hotspot.</p>
<div class="sect2">
<h3 id="find-your-usb-wi-fi-adapter">Find your USB Wi-Fi adapter</h3>
<p>First, we need to find the USB adapter. Run the following command to identify Wi-Fi devices with the Network Manager CLI:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nmcli device</code></pre>
</div>
</div>
<p>You should see output similar to the following:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-text" data-lang="text">DEVICE         TYPE      STATE                   CONNECTION
wlan1          wifi      connected               Example Wi-Fi
lo             loopback  connected (externally)  lo
wlan0          wifi      disconnected            --
p2p-dev-wlan0  wifi-p2p  disconnected            --
eth0           ethernet  unavailable             --</code></pre>
</div>
</div>
<p>In the above output, the USB Wi-Fi module, <code>wlan1</code>, is connected to a Wi-Fi network named "Example Wi-Fi". The built-in Wi-Fi device, <code>wlan0</code>, is not currently in use, so the state currently reads "disconnected".</p>
<p>If your Raspberry Pi has a built-in Wi-Fi module, it should show up by default as <code>wlan0</code>. The first Wi-Fi module you connect should show up as <code>wlan1</code>, and subsequent adapters will display as <code>wlan2</code>, <code>wlan3</code>, and so on. Depending on your specific configuration, your Raspberry Pi might connect to your network using either the USB adapter or the built-in Wi-Fi module.</p>
</div>
<div class="sect2">
<h3 id="create-hotspot-network">Create hotspot network</h3>
<p>Next, we&#8217;ll use the built-in Wi-Fi module to broadcast a hotspot network. Run the following command to create a hotspot, replacing the <code>&lt;hotspot name&gt;</code> and <code>&lt;hotspot password&gt;</code> placeholders with a hotspot name and password of your choice:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nmcli device wifi hotspot ssid &lt;hotspot name&gt; password &lt;hotspot password&gt; ifname wlan0</code></pre>
</div>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">The <code>ifname wlan0</code> option at the end of this command specifies that the hotspot should use the built-in Wi-Fi module, which supports the AP (Access Point) mode required to broadcast a hotspot network. To host a hotspot from a Raspberry Pi that lacks a built-in Wi-Fi module, specify an interface corresponding to a USB adapter that supports AP mode.</div></div>
<p>After creating the hotspot network, your hotspot should automatically become active.</p>
<p>Next, connect to the hotspot Wi-Fi network from your usual computer. Look for a network with an SSID matching the hotspot name you chose in the previous step. Use the password you also provided in that step to authenticate.</p>
<p>Then, connect to your Raspberry Pi using SSH:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-hotspot.local</code></pre>
</div>
</div>
<p>And run the following command to view your current connections:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nmcli connection</code></pre>
</div>
</div>
<p>You should see output similar to the following:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-text" data-lang="text">NAME       UUID                                  TYPE      DEVICE
Hotspot    69d77a03-1cd1-4ec7-bd78-2eb6cd5f1386  wifi      wlan0
lo         f0209dd9-8416-40a0-971d-860d3ff3501b  loopback  lo
Ethernet   4c8098c7-9f7d-4e3e-a27a-70d54235ec9a  ethernet  --
Example 1  f0c4fbcc-ac88-4791-98c2-e75685c70e9f  wifi      --
Example 2  9c6098a7-ac88-40a0-5ac2-b75695c70e9e  wifi      --</code></pre>
</div>
</div>
<p>The connection named <code>Hotspot</code> represents your new hotspot network. The <code>Example 1</code> and <code>Example 2</code> connections above represent saved Wi-Fi connections which are inactive.</p>
</div>
<div class="sect2">
<h3 id="configure-hotspot-network">Configure hotspot network</h3>
<p>Let&#8217;s configure your hotspot network to automatically broadcast whenever your Raspberry Pi boots. When your Raspberry Pi boots, it starts whichever connection has autoconnect enabled with the highest priority. To ensure that your hotspot always starts on boot, we&#8217;ll enable autoconnect for the hotspot and configure a priority higher than any other connection.</p>
<p>Re-run the <code>nmcli connection</code> command above and copy the UUID for your hotspot network from the table. Then, run the following command to view connection properties for your hotspot network, replacing the <code>&lt;hotspot UUID&gt;</code> placeholder with the UUID for your hotspot:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nmcli connection show &lt;hotspot UUID&gt;</code></pre>
</div>
</div>
<p>The output will contain a lot of properties that describe your hotspot network. But we&#8217;re only interested in the following two properties for now:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-text" data-lang="text">connection.autoconnect:                 no
connection.autoconnect-priority:        0</code></pre>
</div>
</div>
<p>Run the following command to change the priority and autoconnect properties for your hotspot, replacing the <code>&lt;hotspot UUID&gt;</code> placeholder with the UUID for your hotspot that you copied to your clipboard before:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nmcli connection modify &lt;hotspot UUID&gt; connection.autoconnect yes connection.autoconnect-priority 100</code></pre>
</div>
</div>
<p>If your command executed successfully, we should see the following new values for those properties when we re-run <code>nmcli connection show &lt;hotspot UUID&gt;</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-text" data-lang="text">connection.autoconnect:                 yes
connection.autoconnect-priority:        100</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="configure-connection-portal">Configure connection portal</h3>
<p>Next, let&#8217;s configure a portal website that allows you to easily connect your Raspberry Pi to a hotel Wi-Fi network from a browser.</p>
<p>Install the following tools:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install python3-flask</code></pre>
</div>
</div>
<p>Then, run the following command to make a directory where we can create our portal, called <code>wifi-portal</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ mkdir ~/wifi-portal</code></pre>
</div>
</div>
<p>Then, navigate into the portal directory:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ cd ~/wifi-portal</code></pre>
</div>
</div>
<p>Open <code>app.py</code> in the portal directory, which contains the logic for the portal website:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano app.py</code></pre>
</div>
</div>
<p>Copy and paste the following code into <code>app.py</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">from flask import Flask,request
import subprocess

app = Flask(__name__)

wifi_device = "wlan1"

@app.route('/')
def index():
    result = subprocess.check_output(["nmcli", "--colors", "no", "-m", "multiline", "--get-value", "SSID", "dev", "wifi", "list", "ifname", wifi_device])
    ssids_list = result.decode().split('\n')
    dropdowndisplay = f"""
        &lt;!DOCTYPE html&gt;
        &lt;html&gt;
        &lt;head&gt;
            &lt;title&gt;Wifi Control&lt;/title&gt;
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h1&gt;Wifi Control&lt;/h1&gt;
            &lt;form action="/submit" method="post"&gt;
                &lt;label for="ssid"&gt;Choose a WiFi network:&lt;/label&gt;
                &lt;select name="ssid" id="ssid"&gt;
        """
    for ssid in ssids_list:
        only_ssid = ssid.removeprefix("SSID:")
        if len(only_ssid) &gt; 0:
            dropdowndisplay += f"""
                    &lt;option value="{only_ssid}"&gt;{only_ssid}&lt;/option&gt;
            """
    dropdowndisplay += f"""
                &lt;/select&gt;
                &lt;p/&gt;
                &lt;label for="password"&gt;Password: &lt;input type="password" name="password"/&gt;&lt;/label&gt;
                &lt;p/&gt;
                &lt;input type="submit" value="Connect"&gt;
            &lt;/form&gt;
        &lt;/body&gt;
        &lt;/html&gt;
        """
    return dropdowndisplay


@app.route('/submit',methods=['POST'])
def submit():
    if request.method == 'POST':
        print(*list(request.form.keys()), sep = ", ")
        ssid = request.form['ssid']
        password = request.form['password']
        connection_command = ["nmcli", "--colors", "no", "device", "wifi", "connect", ssid, "ifname", wifi_device]
        if len(password) &gt; 0:
          connection_command.append("password")
          connection_command.append(password)
        result = subprocess.run(connection_command, capture_output=True)
        if result.stderr:
            return "Error: failed to connect to wifi network: &lt;i&gt;%s&lt;/i&gt;" % result.stderr.decode()
        elif result.stdout:
            return "Success: &lt;i&gt;%s&lt;/i&gt;" % result.stdout.decode()
        return "Error: failed to connect."


if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=80)</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with nano.</p>
<p>Next, let&#8217;s configure your Raspberry Pi to automatically run the Wi-Fi portal after boot. Run the following command to open your <a href="https://en.wikipedia.org/wiki/Cron"><code>cron</code></a> tab, a Linux scheduling tool:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ crontab -e</code></pre>
</div>
</div>
<p>Enter <code>1</code> to use the nano text editor to edit your cron schedule.
Then, add the following line to the file, replacing the <code>&lt;username&gt;</code> placeholder with your Raspberry Pi admin account username:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-md" data-lang="md">@reboot sudo python3 /home/&lt;username&gt;/wifi-portal/app.py</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with nano.</p>
<p>And enter the following command to reboot your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>You&#8217;re now ready to connect to any hotel Wi-Fi network!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="use-the-hotspot">Use the hotspot</h2>
<div class="sectionbody">
<p>You should now have your hotel Wi-Fi hotspot entirely set up. Every time you go to a hotel, repeat the following steps:</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Plug in your Raspberry Pi.</p>
</li>
<li>
<p>Connect your usual computer to the hotspot Wi-Fi connection.</p>
</li>
<li>
<p>Connect a device to the hotspot and visit <a href="http://pi-hotspot.local" class="bare">http://pi-hotspot.local</a>. Select a Wi-Fi network and enter a password if necessary.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images//hotspot/wifi-control-portal.png" alt="The web portal that lets you choose a Wi-Fi network for your Raspberry Pi's upstream data connection"></figure></div>
</li>
<li>
<p>On a device connected to the hotspot, open the captive portal at <a href="http://captive.apple.com" class="bare">http://captive.apple.com</a>. Authenticate to get the Raspberry Pi hotspot network connected to the internet.</p>
</li>
</ol>
</div>
<p>The first time you use another device with the hotspot, you&#8217;ll have to set up the Wi-Fi connection manually. But after that, the device should automatically connect to the hotspot.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">You may have to repeat the captive portal step every 12-48 hours depending on your hotel&#8217;s network setup.</div></div>
</div>
</div>
<div class="sect1">
<h2 id="next-steps">Next steps</h2>
<div class="sectionbody">
<p>Now that you&#8217;ve got your own Wi-Fi hotspot routed through hotel Wi-Fi networks, put it to good use! Watch some movies, browse the internet, and relax.</p>
<p>Now you&#8217;ve relaxed, consider some improvements to make your hotel Wi-Fi hotspot even more convenient. Using a second Raspberry Pi (or home server, if you already have one), you can host a personal VPN on your home network with <a href="https://pivpn.io/">PiVPN</a> and configure your hotspot-hosting Raspberry Pi to connect to it. With a VPN connection, you can protect all devices connected to your hotspot from snooping while connected to insecure guest networks.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[This Raspberry Pi-hosted Wi-Fi hotspot connects to a guest Wi-Fi network, then runs a separate private Wi-Fi network for all of your devices.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/hotspot/hero.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/hotspot/hero.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Block ads at home with Pi-hole</title><link href="https://www.raspberrypi.com/tutorials/running-pi-hole-on-a-raspberry-pi/" rel="alternate" type="text/html" title="Block ads at home with Pi-hole" /><published>2023-10-12T00:00:00+00:00</published><updated>2023-10-12T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/running-pi-hole-on-a-raspberry-pi/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/running-pi-hole-on-a-raspberry-pi/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Internet advertising can often be a nuisance. It takes up valuable bandwidth. It weighs your browser down with trackers. It reports your data back to untrustworthy third parties.</p>
<p>On some devices, like laptops and phones, you can use ad blockers to protect yourself (and your sanity). But on many smart devices, like TVs, refrigerators, <a href="https://revcook.com/products/instaglo-r180-toaster">toasters</a>, and <a href="https://www.kohler.com/en/products/toilets/shop-toilets/numi-2-0-one-piece-elongated-smart-toilet-dual-flush-30754-pa">toilets</a>, you can&#8217;t install an ad blocker.</p>
<p>Pi-hole simplifies ad blocking by operating at the <em>network</em> level, instead of on individual devices. That way, you aren&#8217;t restricted by which devices can install an ad-blocker; instead, you can protect devices on your network from ever accessing ads in the first place.</p>
</div>
</div>
<div class="sect1">
<h2 id="how-does-pi-hole-work">How does Pi-hole work?</h2>
<div class="sectionbody">
<p>Pi-hole blocks ads by acting as a <a href="https://en.wikipedia.org/wiki/DNS_sinkhole">DNS sinkhole</a>.</p>
<p>To understand what a DNS sinkhole is, you need to understand what DNS is. Here are a few key terms:</p>
<div class="dlist">
<dl>
<dt class="hdlist1">Domain Name</dt>
<dd>
<p>unique alphanumeric address of a web resource (e.g. <code>raspberrypi.com</code>)</p>
</dd>
<dt class="hdlist1">IP address</dt>
<dd>
<p>unique numeric address of a web resource (e.g. <code>104.22.23.160</code>)</p>
</dd>
<dt class="hdlist1">DNS</dt>
<dd>
<p>Domain Name System, associates domain names with IP addresses</p>
</dd>
<dt class="hdlist1">DNS server</dt>
<dd>
<p>a server that translates domain names into IP addresses</p>
</dd>
</dl>
</div>
<p>When you type <code>www.raspberrypi.com</code> into your browser, your computer asks a DNS server where to find that domain. The DNS server responds with an IP address (e.g. <code>104.22.23.160</code>). Then your computer queries that IP address for the resource you&#8217;re looking for.</p>
<p>We use domain names because IP addresses aren&#8217;t very human-readable; it&#8217;s a lot easier to read and write "raspberrypi.com" than four bytes' worth of numbers.</p>
<p>Usually, your computer queries a DNS server hosted somewhere on the internet. It might be hosted by your internet provider, a website hosting company, or any company that runs a lot of servers. Your machine submits a domain, and the DNS server returns the IP address corresponding to that domain. The DNS server doesn&#8217;t care if the domain provides something you want (like the article you&#8217;re trying to read) or an ad. It just resolves domains into IP addresses.</p>
<p>Here&#8217;s where Pi-hole comes in. Pi-hole stands between your network and a DNS server. Consider a client device, like your smart toilet, performing a DNS lookup for a domain. The Pi-hole in your network acts like a DNS server; DNS lookups from all client devices, whether that&#8217;s your smart toilet or your phone, go to the Pi-hole.</p>
<p>But Pi-hole doesn&#8217;t store a perfect up-to-date mapping of all domain names to all IP addresses. Instead, Pi-hole queries a <em>real</em> DNS server outside of your network. However, before it queries that real DNS server, Pi-hole checks a blocklist. If the domain passes this filter, Pi-hole requests the IP address from the DNS server, and returns it to the client device on your network. If the domain doesn&#8217;t pass the filter — if it&#8217;s included on the blocklist — Pi-hole returns a non-routable address such as <code>0.0.0.0</code>.</p>
<p>The following diagram shows a lookup via a Pi-hole for the <em>unblocked</em> domain <code>raspberrypi.com</code>:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/dns_success-1024x209.png" alt="A diagram demonstrating a successful DNS lookup via a Pi-hole"></figure></div>
<p>The following diagram shows a lookup via a Pi-hole for the <em>blocked</em> domain <code>raspberryads.com</code>:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/dns_blocked-1024x209.png" alt="A diagram demonstrating a blocked DNS lookup via a Pi-hole"></figure></div>
<p>TL;DR: Pi-hole blocks requests made to ad domains from your network, before the requests ever leave your network. Your client devices <strong>can&#8217;t</strong> connect to domains that host ads, but <strong>can</strong> connect to domains that host useful content.</p>
</div>
</div>
<div class="sect1">
<h2 id="overview">Overview</h2>
<div class="sectionbody">
<p>To install a Pi-hole in your network, you&#8217;ll need to do the following things:</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Configure a Raspberry Pi running Raspberry Pi OS.</p>
</li>
<li>
<p>Set up <a href="https://github.com/pi-hole/pi-hole">Pi-hole</a> software on your Raspberry Pi.</p>
</li>
<li>
<p>Direct DNS queries on your network to your Raspberry Pi.</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>suitable power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the documentation for details</a>)</p>
</li>
<li>
<p>microSD card (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">the documentation for details</a>)</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>USB cable (check your 3D printer for details)</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-a-raspberry-pi">Choose a Raspberry Pi</h3>
<p>You can use any Raspberry Pi model for this. We recommend <a href="https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/">Zero 2 W</a> if you can&#8217;t decide which model to use.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS Lite (32-bit)</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-hole</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
</li>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="connect-via-ssh">Connect via SSH</h2>
<div class="sectionbody">
<p>Open a terminal on your computer. If you use a Windows computer, you might need to install an SSH client; we suggest <a href="https://putty.software/">PuTTY</a>. Enter the following command to connect to your Raspberry Pi, replacing the <code>&lt;username&gt;</code> placeholder with your own username that you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-hole.local</code></pre>
</div>
</div>
<p>If <code>ssh</code> asks you if you&#8217;re sure you want to continue connecting, reply <code>yes</code>. Enter the password you chose during advanced configuration when prompted.</p>
<p>You&#8217;ll know you&#8217;ve connected successfully when you see the following prompt with your configured username and hostname:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">&lt;username&gt;@&lt;hostname&gt;:~ $</code></pre>
</div>
</div>
<p>Now that you&#8217;ve connected to your Raspberry Pi, run two commands to make sure that all of your packages are up to date:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt update
$ sudo apt full-upgrade</code></pre>
</div>
</div>
<p>Once the package update commands finish running, reboot your Raspberry Pi to allow all changes to take effect:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Running this command will disconnect you from the Raspberry Pi SSH session. Wait a few seconds for your Raspberry Pi to reboot, and enter the <code>ssh</code> connection command again to reconnect to your device.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">On most terminals, press the <strong>Up</strong> arrow key, then the <strong>Enter</strong> key to re-run the most recent command.</div></div>
</div>
</div>
<div class="sect1">
<h2 id="install-pi-hole">Install Pi-hole</h2>
<div class="sectionbody">
<p>Run the following single-line command to run the Pi-hole setup script:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ curl -sSL https://install.pi-hole.net | bash</code></pre>
</div>
</div>
<p>The setup script is relatively self-explanatory, but follow these tips if you aren&#8217;t sure how to proceed:</p>
<div class="ulist">
<ul>
<li>
<p>When warned about needing a static IP address, click <strong>Continue</strong> to proceed; we&#8217;ll deal with this later</p>
</li>
<li>
<p>When prompted to select an interface, select <code>wlan0</code> to use your Raspberry Pi&#8217;s Wi-Fi connection</p>
</li>
<li>
<p>When prompted to choose an upstream DNS provider, choose <strong>OpenDNS</strong></p>
</li>
<li>
<p>Include <strong>StevenBlack&#8217;s Unified Hosts List</strong></p>
</li>
<li>
<p>Install the Admin Web Interface</p>
</li>
<li>
<p>Install <code>lighttpd</code> and the required PHP modules to run the Admin Web Interface</p>
</li>
<li>
<p>Enable query logging</p>
</li>
<li>
<p>When prompted to choose a privacy level, choose <strong>Anonymous mode</strong></p>
</li>
</ul>
</div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-10-04-at-15.39.45-1024x630.png" alt="The Installation Complete screen of the Pi-hole setup script"></figure></div>
<p>When you see "Installation complete!", the setup is complete. This screen shows the IP address of your Pi-hole, a link to the admin interface, and your administrator password.</p>
<div class="ulist">
<ul>
<li>
<p>Save this password somewhere safe, like a password manager — you&#8217;ll need it to work with your Pi-hole in the future</p>
</li>
<li>
<p>Save the IP address — you&#8217;ll need it to configure a static IP address shortly</p>
</li>
</ul>
</div>
<p>Pi-hole only provides a single administrator account, so there&#8217;s no username.
Press the <strong>Control</strong> key (<strong>Command</strong> on macOS) and click the link to the admin interface that uses an IP address. It&#8217;ll look something like <code>http://192.168.1.24/admin</code>. Don&#8217;t use the <code>pi.hole</code> domain link yet; until we configure the Pi-hole as our DNS provider, it won&#8217;t work. The link should open in your browser. You can also copy and paste the link into a browser if control + click doesn&#8217;t work in your terminal.
Use the admin password from the setup script output to authenticate. You can now see your Pi-hole admin console! We recommend bookmarking this console for future maintenance.</p>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-network-to-use-your-pi-hole">Configure your network to use your Pi-hole</h2>
<div class="sectionbody">
<div class="admonitionblock warning" role="note"><h5 class="label">warning</h5><div class="inner"><p>The tasks below require you to change global settings in your wireless network. You might break your internet connection (for a little while). Proceed with caution!</p></div></div>
<p>To complete these tasks, visit the admin interface for your router. You can usually access the admin interface through your router&#8217;s IP address. Here are a couple of common ways to find that interface:</p>
<div class="ulist">
<ul>
<li>
<p>Run the following command on your Raspberry Pi to output your router&#8217;s IP address:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nmcli -f IP4.GATEWAY device show wlan0</code></pre>
</div>
</div>
</li>
<li>
<p>Check for a sticker on your router — look for a value called "admin URL" or similar</p>
</li>
</ul>
</div>
<p>Once you&#8217;ve found the IP address, log in to your router&#8217;s admin interface by typing the address (sometimes with the suffix <code>/admin</code>) into your browser. Enter your username and password (if you don&#8217;t know these, you may be able to find them on a sticker on your router).
Now that you&#8217;ve got your Pi-hole configured, you have three choices to use it to block ads. All of them involve getting Pi-hole between your network and the internet:</p>
<div class="ulist">
<ul>
<li>
<p>configure Pi-hole as the DNS server for your network</p>
</li>
<li>
<p>configure Pi-hole as the DHCP provider for your network</p>
</li>
<li>
<p>manually point devices at Pi-hole for DNS</p>
</li>
</ul>
</div>
<p>It&#8217;s easiest to use your Pi-hole as a DNS server. However, some routers don&#8217;t provide a setting to control the default DNS server. If you can&#8217;t set a DNS server, try configuring Pi-hole as your DHCP provider. And if you can&#8217;t do that either, you can always manually point devices at the Pi-hole for DNS — it&#8217;s not as good as full-network ad blocking, but it&#8217;s a lot better than nothing.</p>
</div>
</div>
<div class="sect1">
<h2 id="configure-pi-hole-as-your-networks-dns-server">Configure Pi-hole as your network&#8217;s DNS server</h2>
<div class="sectionbody">
<p>This is the most common way of configuring a Pi-hole. For this method, you&#8217;ll first assign your Raspberry Pi a static IP address from your router&#8217;s interface, then point your router&#8217;s DNS server settings to the Pi-hole&#8217;s static IP address. With this setup, your router controls IP reservations across your network, but devices on the network send DNS queries to your Pi-hole instead of to a DNS server on the internet.</p>
<div class="sect2">
<h3 id="assign-your-raspberry-pi-a-static-ip-address">Assign your Raspberry Pi a static IP address</h3>
<p>IP addresses are unique numeric codes that allow you to directly interact with devices on your network. For instance, many routers automatically assign themselves the first address in the IP block they are using, such as <code>192.168.1.1</code>. Most networks use Dynamic Host Configuration Protocol (DHCP) to assign IP addresses to devices automatically. These IP addresses are known as <strong>dynamic</strong> IP addresses, because they can change at any time.</p>
<p>To run a Pi-hole on your network, we recommend assigning your Pi-hole a <strong>static</strong> IP address. A static IP address never changes. This allows devices on your network always to find the Pi-hole at the same address.</p>
<p>To start, run the following command on your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ hostname -I</code></pre>
</div>
</div>
<p>You should see output similar to the following:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ 192.168.1.24</code></pre>
</div>
</div>
<p>This value is the current (dynamic) IP address of your Raspberry Pi on the network.</p>
<p>To assign a static IP address, you also need the MAC address of your Raspberry Pi. A device&#8217;s MAC address is a hardware identifier that your router uses to uniquely identify it. Run the following command to find the MAC address of your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nmcli -f GENERAL.HWADDR device show wlan0</code></pre>
</div>
</div>
<p>You should see output similar to the following:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">GENERAL.HWADDR:                         A8:42:EA:58:E0:1C</code></pre>
</div>
</div>
<p>The value on the right is the MAC address of your Raspberry Pi.
Now that we know your Raspberry Pi&#8217;s MAC address and IP address, we can configure your router so it always associates the Raspberry Pi&#8217;s MAC address with its current IP address. Effectively, we&#8217;re turning the current dynamic address into a static one using the MAC address.
In your router&#8217;s admin interface, configure a static IP address for your Raspberry Pi. There are several ways to accomplish this, depending on your router:</p>
<div class="ulist">
<ul>
<li>
<p>You might be able to find this setting in the "Advanced" section of the router admin interface. Look for a list called "DHCP Reservations", and enter your Raspberry Pi&#8217;s IP address and MAC address.</p>
</li>
<li>
<p>Look for a list of connected devices and find your Raspberry Pi&#8217;s IP address or MAC address. Select the option to "Always use this IP address" to make the IP address reservation static.</p>
</li>
<li>
<p>Check the documentation for your router model for specific instructions.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="set-pi-hole-as-your-networks-default-dns-server">Set Pi-hole as your network&#8217;s default DNS server</h3>
<p>Once you&#8217;ve assigned your Raspberry Pi a static IP address, you can configure individual devices to use Pi-hole as a DNS server in their network settings. But this process is tedious, and some devices don&#8217;t provide an easily accessible DNS server setting. However, there is an easier way: most routers automatically suggest a DNS server for devices connected to your network. All you have to do is change the suggested server in your router&#8217;s settings, and your entire network should start using your Pi-hole for DNS.</p>
<p>Look for a setting called DNS in your router&#8217;s admin interface. You may be able to find the setting in a section called "Internet", "DHCP", "Internet Connection", or "DDNS".</p>
<p>Enter your Pi-hole&#8217;s IP address in the DNS (or similarly named) field.</p>
<p>If your router provides multiple custom DNS fields, add your Pi-hole address in each field.</p>
<div class="admonitionblock important" role="note"><h5 class="label">important</h5><div class="inner"><p>Whatever you do, don&#8217;t add any separate DNS entries after the Pi-hole entries — this can break Pi-hole&#8217;s ad blocking functionality. When your Pi-hole blocks a domain, it returns a non-routable address such as <code>0.0.0.0</code>, and some devices will query the secondary DNS server when the first server returns such a non-routable address. If your secondary DNS server isn&#8217;t a Pi-hole, every single request blocked by Pi-hole will succeed on the secondary server, and ads will load as if you weren&#8217;t running an ad blocker at all.</p></div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-pi-hole-as-your-networks-dhcp-provider">Configure Pi-hole as your network&#8217;s DHCP provider</h2>
<div class="sectionbody">
<p>If your router doesn&#8217;t support configuration for static IP addresses or DNS servers, you may still be able to use your Pi-hole automatically across your network. First, check whether you can change the network DHCP server in your router settings. If you can, you can use your Pi-hole <em>both</em> as a DNS server <em>and</em> as the DHCP server that handles IP address reservations across your network.</p>
<p>First, navigate to the Pi-hole admin console. If you type your Raspberry Pi&#8217;s IP address into your browser, it should redirect you there.</p>
<p>In the left side menu, select the "Settings" page.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-06-15-at-16.39.42.png" alt="DHCP settings on the Pi-hole Settings page"></figure></div>
<p>In the DHCP tab, in the "DHCP Settings" block, check the "DHCP server enabled" box.</p>
<p>Pi-hole should pre-populate the IP address range with the IP block that your router currently uses, and the router IP address with the router&#8217;s current IP address. You can leave these values as they are. Click the <strong>Save</strong> button in the bottom left to start hosting a DHCP server from Pi-hole.</p>
<p>Finally, visit your router&#8217;s admin interface, and set your Pi-hole&#8217;s IP address as the DHCP provider for your network. When your Pi-hole is functioning as the DHCP provider, your router delegates all IP-related tasks to it. This includes DNS server configuration, so your Pi-hole can suggest <em>itself</em> as the default DNS server for all devices on your network. Check the documentation for your router model for specific instructions.</p>
</div>
</div>
<div class="sect1">
<h2 id="manually-point-devices-at-pi-hole-for-dns">Manually point devices at Pi-hole for DNS</h2>
<div class="sectionbody">
<p>On many devices, you can configure DNS settings in Wi-Fi preferences. Look in the "Advanced" section of your Wi-Fi or wired connection preferences for a DNS server setting. Put your Raspberry Pi&#8217;s IP address in this field. Your device should immediately start issuing DNS queries to the Pi-hole.</p>
<p>Unless you&#8217;ve configured a static IP address for your Raspberry Pi, this IP address can change at any time without warning. Follow the instructions under "Assign your Raspberry Pi a static IP address" in the DNS section above to configure a static IP address — this will prevent your device from losing its connection to the Pi-hole (and most of the internet!) when your Pi-hole&#8217;s dynamic IP address changes.</p>
</div>
</div>
<div class="sect1">
<h2 id="is-my-pi-hole-working">Is my Pi-hole working?</h2>
<div class="sectionbody">
<p>With a Pi-hole acting as the DNS server for your network, many pages will load without ads at all. Most privacy-invading trackers won&#8217;t work either. You&#8217;ll still see cookie and app install banners, because those can&#8217;t be blocked at the DNS level.
To check to see if your Pi-hole is working correctly:</p>
<div class="ulist">
<ul>
<li>
<p>Check out <a href="https://adblock-tester.com/">Adblock Tester</a>. Without Pi-hole, many browsers score near 0; with Pi-hole, you should see a score at or near 100.</p>
</li>
<li>
<p>Try visiting <a href="http://pi.hole/admin/login.php">http://pi.hole/admin/login.php</a>. Pi-hole always routes the <code>pi.hole</code> domain to your Raspberry Pi when you use Pi-hole as your DNS server.</p>
</li>
<li>
<p>Visit any site where you normally see ads and visually confirm that ads are no longer there.</p>
</li>
<li>
<p>Check the proportion of "queries blocked" on the Pi-hole dashboard. Many networks see between 10% and 50% of queries blocked!</p>
</li>
<li>
<p>Check the DNS server used by other computers in your network. You should be able to find this information in "Details" or "Advanced" Wi-Fi settings. If you see your Raspberry Pi&#8217;s IP address, your configuration worked!</p>
</li>
</ul>
</div>
<p>If you&#8217;ve completed all of the setup steps but you&#8217;re still seeing ads (or, worse, DNS queries don&#8217;t resolve), try the trusty solution of turning your router off and on again. This should disconnect all devices from your network and renew all DHCP leases, putting your new settings into effect for every device.
Congratulations! Your home network is now protected from ads. Put a slice of bread in your smart toaster, watch a movie on your smart TV, and flush your smart toilet in the comfort of privacy and security.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Pi-hole blocks internet ads at your router, removing bandwidth-sucking and privacy-invading ads from your whole network.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/MAGPI_ROUTER_002-800x533.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/MAGPI_ROUTER_002-800x533.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Plug-and-play Raspberry Pi USB webcam</title><link href="https://www.raspberrypi.com/tutorials/plug-and-play-raspberry-pi-usb-webcam/" rel="alternate" type="text/html" title="Plug-and-play Raspberry Pi USB webcam" /><published>2023-10-11T00:00:00+00:00</published><updated>2023-10-11T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/plug-and-play-raspberry-pi-usb-webcam/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/plug-and-play-raspberry-pi-usb-webcam/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>This tutorial was written for Raspberry Pi OS Bullseye and has not yet been updated for our latest operating system, Bookworm. There have been <a href="https://www.raspberrypi.com/news/bookworm-the-new-version-of-raspberry-pi-os/">major changes</a> between these two OS releases, including changes to networking. You can still follow this tutorial, but you will have to download and install the "legacy" version of the operating system.</p></div></div>
<p>Many of us have become all too familiar with Zoom, Teams, Skype, and countless other video calling applications in recent years. They&#8217;re essential to see our coworkers when we work remotely. At times, they have been the only way to see our loved ones. Unfortunately, many laptops and USB webcams use cameras that are, at best, mediocre.</p>
<p>This tutorial helps you create a USB webcam using a Raspberry Pi and a Raspberry Pi camera. Plug it into any Mac, Windows, or Linux computer to use it as a video camera.</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>cable to connect your Raspberry Pi to your computer for power <em>and</em> data</p>
</li>
<li>
<p>microSD card</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>Raspberry Pi camera</p>
</li>
<li>
<p>Raspberry Pi camera cable</p>
</li>
<li>
<p>Raspberry Pi case with camera mount</p>
</li>
<li>
<p>laptop mount or tripod</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up as a webcam.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi">Choose the right Raspberry Pi</h3>
<p>For this tutorial, we&#8217;ll use a Raspberry Pi Zero 2 W. Since this model supports <a href="https://en.wikipedia.org/wiki/USB_On-The-Go">USB On-The-Go (OTG)</a>, we can use one cable for both power and data.</p>
</div>
<div class="sect2">
<h3 id="choose-the-right-camera">Choose the right camera</h3>
<p>For this tutorial, we&#8217;ll use a <a href="https://www.raspberrypi.com/products/raspberry-pi-high-quality-camera/">Raspberry Pi Camera Module 3</a>.</p>
<p>You&#8217;ll also need a cable to connect your camera with your Raspberry Pi. For all Raspberry Pi Zero models, we recommend the <a href="https://www.raspberrypi.com/products/camera-cable/">Raspberry Pi Camera Cable</a>.</p>
</div>
<div class="sect2">
<h3 id="choose-the-right-case">Choose the right case</h3>
<p>A Raspberry Pi case with a camera mount keeps your webcam safe from everyday wear and tear.</p>
<p>You could 3D print these <a href="https://www.printables.com/model/379839-raspberry-pi-zero-2-webcam-mount-for-v3-and-m12-ca">Raspberry Pi Zero 2 W case files</a>. This case requires <a href="https://www.amazon.co.uk/HSeaMall-360PCS-Standoff-Accessories-Assortment/dp/B07CJGT93C">a combination of M2 and M2.5 nylon hex spacers</a> for assembly.</p>
<p>There are also many third-party Raspberry Pi cases available on the market, and some include a camera mount.</p>
<p>Since you&#8217;ll connect the entire setup to your computer as a webcam, you should also consider a <a href="https://www.amazon.co.uk/Goshyda-Laptop-Conference-Holder-Meeting-default/dp/B09KZX5QQY">laptop mount</a> or tripod to make it easier to set up your webcam.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS (Other) &gt; Raspberry Pi OS (Legacy) Lite</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-webcam</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
</ul>
</div>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard and mouse. It&#8217;s perfect if your Raspberry Pi is located in a hard-to-reach location, like behind a train times display.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the hostname you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi&#8217;s IP address instead.</p>
<p>For more information about finding your IP address and remote accessing your Raspberry Pi, see <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">the remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-via-ssh">Connect via SSH</h3>
<p>Open a terminal session on <em>your usual computer</em>. To access your Raspberry Pi via SSH, run the following command, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-webcam.local</code></pre>
</div>
</div>
<p>The first time you do this, confirm that you want to connect. When asked, use the password you created in Raspberry Pi Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-webcam.local
The authenticity of host 'pi-webcam.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-webcam.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-webcam.local's password:
Linux pi-webcam 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Oct 26 09:41:00 2023
&lt;username&gt;@pi-webcam:~ $</code></pre>
</div>
</div>
<p>Now that you&#8217;ve connected to your Raspberry Pi, run two commands to make sure that all of your packages are up to date:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt update
$ sudo apt full-upgrade</code></pre>
</div>
</div>
<p>Once the package update commands finish running, reboot your Raspberry Pi to allow all changes to take effect:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Running this command will disconnect you from the Raspberry Pi SSH session. Wait a few seconds for your Raspberry Pi to reboot, and enter the <code>ssh</code> connection command again to reconnect to your device.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">On most terminals, press the <strong>Up</strong> arrow key, then the <strong>Enter</strong> key to re-run the most recent command.</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="set-up-and-install-required-software">Set up and install required software</h2>
<div class="sectionbody">
<p>Now that your Raspberry Pi is up and running, let&#8217;s instruct your Raspberry Pi to act as a OTG (On-The-Go) USB device when attached to another computer. We&#8217;ll do this by adding to the <code>/boot/firmware/config.txt</code> file. Append to the file with the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ echo "dtoverlay=dwc2,dr_mode=otg" | sudo tee -a /boot/firmware/config.txt</code></pre>
</div>
</div>
<p>Our next step is to install a few prerequisite programs:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install git meson libcamera-dev libjpeg-dev</code></pre>
</div>
</div>
<p><strong>Meson</strong> is an open source build system that we&#8217;ll use to put together the camera software later. <strong>Libcamera</strong> and <strong>Libjpeg</strong> help your Raspberry Pi use your camera. Type <strong>y</strong> to confirm that you&#8217;d like to install the programs.</p>
<p>Next, download the <strong>UVC gadget</strong> software. This helps your Raspberry Pi stream video over USB:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ git clone https://gitlab.freedesktop.org/camera/uvc-gadget.git</code></pre>
</div>
</div>
<p>Navigate to the downloaded folder:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ cd uvc-gadget</code></pre>
</div>
</div>
<p>We now need to make, build, and install the software with the following commands:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ make uvc-gadget
$ cd build
$ sudo meson install
$ sudo ldconfig</code></pre>
</div>
</div>
<p>The last command, <code>ldconfig</code>, typically runs after installing new libraries or updating existing ones. It helps Raspberry Pi OS properly link to new libraries.</p>
<p>Next, create a script that will run each time your Raspberry Pi is powered on in order to set everything up. Use the <code>nano</code> text editor to create a bash script:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano ~/.rpi-uvc-gadget.sh</code></pre>
</div>
</div>
<p>Copy and paste the following code into the text editor:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">#!/bin/bash

# Variables we need to make things easier later on.

CONFIGFS="/sys/kernel/config"
GADGET="$CONFIGFS/usb_gadget"
VID="0x0525"
PID="0xa4a2"
SERIAL="0123456789"
MANUF=$(hostname)
PRODUCT="UVC Gadget"
BOARD=$(strings /proc/device-tree/model)
UDC=`ls /sys/class/udc` # will identify the 'first' UDC

# Later on, this function is used to tell the usb subsystem that we want
# to support a particular format, framesize and frameintervals
create_frame() {
	# Example usage:
	# create_frame &lt;function name&gt; &lt;width&gt; &lt;height&gt; &lt;format&gt; &lt;name&gt; &lt;intervals&gt;

	FUNCTION=$1
	WIDTH=$2
	HEIGHT=$3
	FORMAT=$4
	NAME=$5

	wdir=functions/$FUNCTION/streaming/$FORMAT/$NAME/${HEIGHT}p

	mkdir -p $wdir
	echo $WIDTH &gt; $wdir/wWidth
	echo $HEIGHT &gt; $wdir/wHeight
	echo $(( $WIDTH * $HEIGHT * 2 )) &gt; $wdir/dwMaxVideoFrameBufferSize
	cat &lt;&lt;EOF &gt; $wdir/dwFrameInterval
$6
EOF
}

# This function sets up the UVC gadget function in configfs and binds us
# to the UVC gadget driver.
create_uvc() {
	CONFIG=$1
	FUNCTION=$2

	echo "	Creating UVC gadget functionality : $FUNCTION"
	mkdir functions/$FUNCTION

	create_frame $FUNCTION 640 480 uncompressed u "333333
416667
500000
666666
1000000
1333333
2000000
"
	create_frame $FUNCTION 1280 720 uncompressed u "1000000
1333333
2000000
"
	create_frame $FUNCTION 1920 1080 uncompressed u "2000000"
	create_frame $FUNCTION 640 480 mjpeg m "333333
416667
500000
666666
1000000
1333333
2000000
"
	create_frame $FUNCTION 1280 720 mjpeg m "333333
416667
500000
666666
1000000
1333333
2000000
"
	create_frame $FUNCTION 1920 1080 mjpeg m "333333
416667
500000
666666
1000000
1333333
2000000
"

	mkdir functions/$FUNCTION/streaming/header/h
	cd functions/$FUNCTION/streaming/header/h
	ln -s ../../uncompressed/u
	ln -s ../../mjpeg/m
	cd ../../class/fs
	ln -s ../../header/h
	cd ../../class/hs
	ln -s ../../header/h
	cd ../../class/ss
	ln -s ../../header/h
	cd ../../../control
	mkdir header/h
	ln -s header/h class/fs
	ln -s header/h class/ss
	cd ../../../

	# This configures the USB endpoint to allow 3x 1024 byte packets per
	# microframe, which gives us the maximum speed for USB 2.0. Other
	# valid values are 1024 and 2048, but these will result in a lower
	# supportable framerate.
	echo 2048 &gt; functions/$FUNCTION/streaming_maxpacket

	ln -s functions/$FUNCTION configs/c.1
}

# This loads the module responsible for allowing USB Gadgets to be
# configured through configfs, without which we can't connect to the
# UVC gadget kernel driver
echo "Loading composite module"
modprobe libcomposite

# This section configures the gadget through configfs. We need to
# create a bunch of files and directories that describe the USB
# device we want to pretend to be.

if
[ ! -d $GADGET/g1 ]; then
	echo "Detecting platform:"
	echo "  board : $BOARD"
	echo "  udc   : $UDC"

	echo "Creating the USB gadget"

	echo "Creating gadget directory g1"
	mkdir -p $GADGET/g1

	cd $GADGET/g1
	if
[ $? -ne 0 ]; then
		echo "Error creating usb gadget in configfs"
		exit 1;
	else
		echo "OK"
	fi

	echo "Setting Vendor and Product ID's"
	echo $VID &gt; idVendor
	echo $PID &gt; idProduct
	echo "OK"

	echo "Setting English strings"
	mkdir -p strings/0x409
	echo $SERIAL &gt; strings/0x409/serialnumber
	echo $MANUF &gt; strings/0x409/manufacturer
	echo $PRODUCT &gt; strings/0x409/product
	echo "OK"

	echo "Creating Config"
	mkdir configs/c.1
	mkdir configs/c.1/strings/0x409

	echo "Creating functions..."

	create_uvc configs/c.1 uvc.0

	echo "OK"

	echo "Binding USB Device Controller"
	echo $UDC &gt; UDC
	echo "OK"
fi

# Run uvc-gadget. The -c flag sets libcamera as a source, arg 0 selects
# the first available camera on the system. All cameras will be listed,
# you can re-run with -c n to select camera n or -c ID to select via
# the camera ID.
uvc-gadget -c 0 uvc.0</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with <code>nano</code>.</p>
<p>Use the following command to make the script executable:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo chmod +x ~/.rpi-uvc-gadget.sh</code></pre>
</div>
</div>
<p>To execute this script every time the device boots, add to the <code>/etc/rc.local</code> file. Raspberry Pi OS always executes this file after boot. Edit <code>/etc/rc.local</code> using the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano /etc/rc.local</code></pre>
</div>
</div>
<p>Add the following command to execute our script above the <code>exit 0</code> line, replacing the <code>&lt;username&gt;</code> placeholder with the username you specified in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ /home/&lt;username&gt;/.rpi-uvc-gadget.sh &amp;</code></pre>
</div>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">If you&#8217;re not sure what your username is, exit <code>nano</code> with <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> and run the <code>whoami</code> command. This command outputs your username.</div></div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with <code>nano</code>. The file should now look like this:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if
[ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

/home/&lt;username&gt;/.rpi-uvc-gadget.sh &amp;

exit 0</code></pre>
</div>
</div>
<p>Finally, shut down your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo shutdown -h now</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="package-it-all-up-in-a-case">Package it all up in a case</h2>
<div class="sectionbody">
<p>Connect your camera to your Raspberry Pi with the ribbon cable (see <a href="https://www.raspberrypi.com/documentation/accessories/camera.html#connecting-the-camera">here</a> for how to do this).</p>
<p>Put your Raspberry Pi and the connected camera into your case. To assemble the case, fasten together the camera, Raspberry Pi, and 3D-printed case using M2.5 and M2 hex nylon standoffs, nuts and bolts, as this image shows:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-03-21-at-11.16.55-800x565.png" alt="Packaging the entire webcam together in a 3D printed case"></figure></div>
<p>The 3D printed case fits any standard cold shoe camera mount:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-03-20-at-16.48.27-300x256.png" alt="A laptop mount compatible with the recommended 3D printed case's cold shoe camera mount"></figure></div>
</div>
</div>
<div class="sect1">
<h2 id="use-your-raspberry-pi-webcam">Use your Raspberry Pi webcam</h2>
<div class="sectionbody">
<p>With your Raspberry Pi configured to run as a USB webcam anytime you plug it in to a computer, all that remains is to use it.</p>
<div class="admonitionblock important" role="note"><h5 class="label">important</h5><div class="inner"><p>If you&#8217;re using a Raspberry Pi Zero 2 W, connect your microUSB cable to the microUSB <em>data</em> port on your Raspberry Pi, not the power port. The power port only supports power.</p></div></div>
<p>Plug your Raspberry Pi into your computer. Allow device access on any OS prompts that pop up. Open your favourite video conferencing software and start a meeting. Find your Raspberry Pi webcam in your video options, and set it as your camera. Congratulations&#8201;&#8212;&#8201;you&#8217;re now ready to use your new webcam for video calls!</p>
</div>
</div>
<div class="sect1">
<h2 id="next-steps">Next steps</h2>
<div class="sectionbody">
<p>Looking to take your webcam to the next level? Check out these ideas to make your webcam even better.</p>
<p>Want to impress your friends with a crispy, high-quality camera feed? The Raspberry Pi High Quality Camera has a higher resolution and is compatible with any standard tripod:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/ON-TRIPOD-1024x683.jpg" alt="Raspberry Pi High Quality M12 Mount Camera"></figure><figcaption><em>Raspberry Pi High Quality M12 Mount Camera</em></figcaption></div>
<p>Not happy with your webcam case? The <a href="https://github.com/maxbbraun/pisight">piSight project by Max Braun</a> uses the casing from the iconic Apple iSight. This project replaces the 25-year-old iSight&#8217;s innards with a Raspberry Pi Zero 2 W and Camera Module 3.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/8-800x601.jpg" alt="piSight. We think you're going to love it."></figure><figcaption><em>piSight. We think you&#8217;re going to love it.</em></figcaption></div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/6-800x1066.jpg" alt="piSight innards"></figure><figcaption><em>plenty of room for better camera quality without the space heater included in the original iSight</em></figcaption></div>
<p>Check out our blog <a href="https://www.raspberrypi.com/news/how-to-build-your-own-raspberry-pi-webcam">here</a> to read all about it, and find all the necessary 3D print files available for free <a href="https://www.printables.com/model/418381-webcam-project-using-an-original-apple-isight-came">here</a>.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Webcams are generally low in quality and low in resolution, so we've made a tutorial to show you how to build your own high-quality Raspberry Pi webcam.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/Camera-Module-3-webcam-800x533.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/Camera-Module-3-webcam-800x533.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Build your own weather satellite receiving station</title><link href="https://www.raspberrypi.com/tutorials/build-your-own-weather-satellite-receiving-station/" rel="alternate" type="text/html" title="Build your own weather satellite receiving station" /><published>2023-10-11T00:00:00+00:00</published><updated>2023-10-11T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/build-your-own-weather-satellite-receiving-station/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/build-your-own-weather-satellite-receiving-station/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>You can create all kinds of fun projects when you pair a Raspberry Pi with a low-cost USB Software Defined Radio (SDR). An SDR is essentially a radio wave receiver that can pick up signals from a variety of frequencies, including digital television, AM, FM and DAB radio broadcasts, and <a href="https://www.raspberrypi.com/tutorials/build-your-own-raspberry-pi-flight-tracker/">aircraft transponders</a>.</p>
<p>This tutorial focuses on the signals sent by the many weather satellites orbiting planet Earth. We will create our own antenna in order to receive those signals, then we will use open source software called <a href="https://github.com/jekhokie/raspberry-noaa-v2">raspberry-noaa-v2</a> to decode those signals on a Raspberry Pi.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/NOAA-19-20230810-100631-MSA-precip.jpg" alt="A fine day across much of England and Wales"></figure></div>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi 4</p>
</li>
<li>
<p>suitable Raspberry Pi power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the power supply documentation for details</a>)</p>
</li>
<li>
<p>microSD card</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>USB Software Defined Radio (SDR) receiver (we used this <a href="https://www.amazon.co.uk/NooElec-NESDR-Mini-Previously-Compatible/dp/B009U7WZCA/">NESDR Mini TV28T v2) USB RTL-SDR, DVB-T &amp; ADS-B Receiver Set</a>)</p>
</li>
<li>
<p>Raspberry Pi 4 model B case</p>
</li>
<li>
<p>5 metres of 8mm Microbore Copper Tube (we used this <a href="https://www.amazon.co.uk/Metre-Coil-Table-Microbore-Copper/dp/B00KJCTIAW/">these</a>, sold in a pack of 10)</p>
</li>
<li>
<p><a href="https://www.amazon.co.uk/sourcingmap%C2%AE-Female-Pigtail-Adapter-23-5cm-Black/dp/B00K85HHTE">MCX Male to BNC Female RG316 Low Loss Pigtail Adapter 23.5cm Cable</a></p>
</li>
<li>
<p>BNC Male to BNC Female RG58 Coax Cable (the length of this cable depends on where you place your antenna. We used this <a href="https://www.amazon.co.uk/BOOBRIE-Female-Extension-Broadcast-Security/dp/B09F2KHF8B/">10 metre length</a></p>
</li>
<li>
<p>1.5 metre length of white plastic <a href="https://www.screwfix.com/p/floplast-solvent-weld-waste-pipe-white-40mm-x-3m/44310">40mm waste pipe</a></p>
</li>
<li>
<p>File or sandpaper</p>
</li>
<li>
<p>Solder</p>
</li>
<li>
<p>4 x 2mm by 8mm self tapping screws</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up as a weather receiving station.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi">Choose the right Raspberry Pi</h3>
<p>Version two of the raspberry-noaa software was developed and tested with a Raspberry Pi 4; we can&#8217;t guarantee compatibility with older Raspberry Pi models. For this tutorial, we&#8217;ll use a <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi 4 Model B</a>.</p>
</div>
<div class="sect2">
<h3 id="tools-required-for-the-antenna-build">Tools required for the antenna build:</h3>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">You can construct the antenna without using 3D printed parts, but a 3D printer makes the build process much simpler. 3D printed parts should eliminate alignment issues that can present a challenge for some makers.</div></div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">If you plan on placing your antenna outside, we recommend ABS filament due to its greater resistance to direct sunlight than other materials.</div></div>
<div class="ulist">
<ul>
<li>
<p>A 3D printer.</p>
</li>
<li>
<p>Hand saw or chop saw (for cutting the waste pipe to length)</p>
</li>
<li>
<p>Hacksaw (for cutting 8mm copper tube to length)</p>
</li>
<li>
<p>Glue (suitable for plastics and wood)</p>
</li>
<li>
<p>Small screwdriver (for self tapping screws)</p>
</li>
<li>
<p>8mm drill bit (any general purpose drill bit should do)</p>
</li>
<li>
<p>Wire cutters</p>
</li>
<li>
<p>Tape measure</p>
</li>
<li>
<p>Pencil</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="3d-printed-parts">3D printed parts</h3>
<p>Download this tutorial&#8217;s <code>.stl</code> files for free from <a href="https://www.printables.com/model/549255-weather-satellite-receiving-station-antenna">printables.com/model/549255-weather-satellite-receiving-station-antenna</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="antenna-construction">Antenna construction</h2>
<div class="sectionbody">
<p>We&#8217;ve updated a <a href="http://metsat.gogan.org/ant_qha.htm">project by Steve Blackmore</a> to make our own antenna.</p>
<p>We will make a Quadrifilar Helix Antenna (QHA) to receive weather satellite radio signals. The key feature of a QHA is the helical (spiralled) shape, which allows the antenna to capture signals from all directions. The term "Quadrifilar" means it has four conductors (wires). We&#8217;ll wrap the wires around the helix to provide four separate paths for the signal to travel. The QHA is a circularly polarised antenna, so it can receive signals in horizontal and vertical planes. This allows the antenna to maintain efficiency regardless of the antenna&#8217;s orientation.</p>
<p>Our antenna consists of a single plastic mast with 3D-printed parts to hold the copper conductors in their correct orientation. We&#8217;ll ultimately connect the antenna to the USB SDR connected to our Raspberry Pi.</p>
<p>The following diagram illustrates the exact dimensions that are important to the finished antenna:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Dimnsions.png" alt="A diagram showing the dimensions of the finished antenna"></figure></div>
</div>
</div>
<div class="sect1">
<h2 id="print-parts">Print parts</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/3D_printed_parts-1024x576.jpg" alt="3D printed rings and caps"></figure></div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">The STL files for this project are available for free at <a href="https://www.printables.com/model/549255-weather-satellite-receiving-station-antenna">printables.com/model/549255-weather-satellite-receiving-station-antenna</a>.</div></div>
<p>First, let&#8217;s print out the supports.</p>
<p>Print the pieces using ABS filament using the right settings for your printer. We printed ours using a 0.8mm nozzle, 0.4mm layer height, and 100% infill for maximum strength.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">The mounting method and location of your antenna is up to you, but we&#8217;ve included a simple test stand for you to print and glue to a board for basic installation.</div></div>
</div>
</div>
<div class="sect1">
<h2 id="center-mast">Center mast</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/chop-1-1024x576.jpg" alt="Cut 1.5 metres of waste pipe"></figure></div>
<p>Measure and cut a 1.5 metre length of 40mm waste pipe to make the mast. Then, using a suitably straight edged item — like a long spirit level — draw a line down the length of the mast.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/centre_line-1024x576.jpg" alt="Draw a line down the length of the mast"></figure></div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">Hold the pipe firmly in place on a flat surface with the straight edge against the pipe to accurately draw the line down the middle of the pipe.</div></div>
<p>Next, measuring from one end of the pipe, mark the line at three points: 25mm, 925mm, and 1025mm. This is where we&#8217;ll mount the conductors.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-10-at-10.36.14-1024x448.png" alt="Mark the points where we'll mount the conductors"></figure></div>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">Accurate measurements maximise the efficiency, gain, and radiation pattern of your antenna. Even small deviations from the intended dimensions can result in significant degradation of the antenna&#8217;s performance!</div></div>
</div>
</div>
<div class="sect1">
<h2 id="conductors">Conductors</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/conductors-1024x576.jpg" alt="Conductors"></figure></div>
<p>Our conductors are made from 8mm microbore copper tubing. Using a hacksaw, cut the tube to the following lengths:</p>
<div class="ulist">
<ul>
<li>
<p>Four 85mm lengths for the top horizontal elements</p>
</li>
<li>
<p>Two 185mm lengths for the bottom horizontal tubes</p>
</li>
<li>
<p>Two 898mm lengths for the short helix elements</p>
</li>
<li>
<p>Two 995mm lengths for the long helix elements</p>
</li>
</ul>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">When you&#8217;ve cut all the pieces to length, roll them between two sheets of flat wood board, such as MDF or plywood, to straighten out any bends in the pipes.</div></div>
<p>Take the four 85mm lengths and drill a 3mm hole approximately 5mm from one end of each length. These holes are for the self-tapping screws that will hold the wiring in place.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/drill-1024x576.jpg" alt="Protect your drilling surface with scrap wood"></figure><figcaption><em>When drilling holes for the self-tapping screws, protect your drilling surface with scrap wood</em></figcaption></div>
</div>
</div>
<div class="sect1">
<h2 id="assembly">Assembly</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/top_assembly-1024x576.jpg" alt="Slide the top conductor ring onto the top of the mast"></figure></div>
<p>Take the 3D-printed top conductor ring and slide it onto the top of the mast, lining up one of the four holes with the first mark you made 25mm from the end. Align the mark exactly onto the centre of the hole; this should leave 10mm of mast exposed at the end.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">The cap is designed to only fit 10mm onto the mast, so you can push fit the cap on the end.</div></div>
<p>Next, use the ring to align the drill bit and drill four 8mm holes in the mast 90 degrees apart from each other:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/drillx4-1024x576.jpg" alt="Drill four 8mm holes into the mast at the conductor ring"></figure></div>
<p>Take the lower conductor ring and slide it into position at the mark you made at 925mm.</p>
<p>Do the same with the bottom ring at the 1025mm mark.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/lower_rings-1024x576.jpg" alt="Attaching the 925mm and 1025mm conductor rings"></figure></div>
<p>Take extra care during this stage to make sure you correctly align the 3D printed pieces:</p>
<div class="ulist">
<ul>
<li>
<p>align the 925mm ring with the element hole, just like the upper conductor ring</p>
</li>
<li>
<p>align the bottom ring with the small, flush alignment hole</p>
</li>
</ul>
</div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-10-at-13.30.08-1024x646.png" alt="Aligning the middle and buttom rings"></figure></div>
<p>When you are happy with all your measurements and positioning, drill two 8mm holes in the middle and lower rings.</p>
<p>Next:</p>
<div class="ulist">
<ul>
<li>
<p>push the four 85mm copper tubes into the top ring</p>
</li>
<li>
<p>push the two 185mm copper tubes into the bottom ring</p>
</li>
</ul>
</div>
<p>Your tubes should extend 200mm from the centre of the pipe on either side:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/200_top-1024x576.jpg" alt="Tubes should extend 200mm from the center of the pipe on either side"></figure></div>
<p>Taking into account the helix shapes, the two long helix elements will be 1012mm long with the corner pieces attached, and the two short helix elements will be 913mm long. Combining those lengths with the helix shaping gives the measurements shown in the previous side view.</p>
<p>Next, drill a 7mm hole approximately 100mm from the end of the mast inline with the cable management holes in the lower conductor rings.</p>
<p>Take your RG58 coax cable and cut off the male connector end&#8201;&#8212;&#8201;we won&#8217;t need it.</p>
<p>Feed the cable into the mast through the drilled hole and out of the end.</p>
<p>Use your wire cutters to strip back the outer plastic jacket on the exposed end by about 50mm. Then, wind the outer woven metal braided wires into one wire.</p>
<p>Remove the insulation layer surrounding the central solid copper wire.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/wiring-1024x576.jpg" alt="Wire the copper cables through the mast"></figure></div>
<p>Next, pass the central solid copper wire in the RG58 coax cable through the drilled holes at the end of one of the long helix element loops. Wire it all the way through the end of one of the short helix element loops.</p>
<p>Pass the outer woven metal braided wires through the remaining holes on the other short helix element loop and long helix element loop.</p>
<p>Hold the wires in place with the four self-tapping screws:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/wires-1024x576.jpg" alt="Hold the wires in place on the helix elements with self-tapping screws"></figure></div>
<p>Finally, we need to create a <strong>balun</strong>: a device that helps connect balanced antennas to unbalanced coaxial cables by converting the two transmission line configurations. This plays a crucial role in maintaining signal quality, reducing interference, and optimising the performance of any antenna.</p>
<p>Wind the coax cable around the mast four times, then place a cable management ring just below it to hold it in place. To do this, remove the two lower conductor 3D printed rings attached earlier (this is temporary, we&#8217;ll put them back on in the next step).</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">Add a small amount of glue to keep the coax cable in place.</div></div>
<p>Now your balun should look like this:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-10-at-15.02.14.png" alt="Creating a balun to improve signal"></figure></div>
<p>Slide on the mid ring, another cable management ring, and replace the two lower rings.</p>
<p>Slide the two 185mm lengths of copper back into place.</p>
<p>Push-fit four of the solder ring elbows.</p>
<p>Attach the two long and two short helix elements into place.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">Bend the tubes slightly if needed to make sure they fit. The mid ring will help you create a smooth shape. Don&#8217;t forget to pop the cap on!</div></div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/bottom-1024x872.png" alt="The bottom of the antenna"></figure><figcaption><em>Bottom</em></figcaption></div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/middle-1024x872.png" alt="The middle of the antenna"></figure><figcaption><em>Middle</em></figcaption></div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/top-1024x872.png" alt="The top of the antenna"></figure><figcaption><em>Top</em></figcaption></div>
<p>Look down at the antenna from the top. It should appear circular in shape:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-08-at-10.01.59-1024x860.png" alt="The antenna should appear circular when viewed from above"></figure><figcaption><em>View from above</em></figcaption></div>
<p>Now is a good time to remeasure (from the center of each element):</p>
<div class="ulist">
<ul>
<li>
<p>The two long helix elements (with the corner pieces attached) should measure 1012mm long.</p>
</li>
<li>
<p>The two short helix elements should measure 913mm long.</p>
</li>
</ul>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">Some elbow joints are different from others, so you may have to trim the tubes to get the correct lengths.</div></div>
<p>When you&#8217;re happy with the placement, use a small amount of solder and a blow torch to weld all 16 connections between the tubes and corner joints.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/solder-1024x576.jpg" alt="Once you've trimmed to the appropriate measurements"></figure><figcaption><em>Soldering connections</em></figcaption></div>
<p>If you chose to 3D print the antenna stand, slide the mast into place and you&#8217;re done!</p>
<p>If you opted to use your own antenna stand, it&#8217;s time to figure out another way to mount it.</p>
<p>Regardless of the method you use, position it with an elevated, clear, and unobstructed view of the sky.</p>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS Lite (32-bit)</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-weather</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
</li>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard and mouse. It&#8217;s perfect if your Raspberry Pi is located in a hard-to-reach location, like behind a train times display.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the hostname you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi&#8217;s IP address instead.</p>
<p>For more information about finding your IP address and remote accessing your Raspberry Pi, see <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">the remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-via-ssh">Connect via SSH</h3>
<p>Open a terminal session on <em>your usual computer</em>. To access your Raspberry Pi via SSH, run the following command, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-weather.local</code></pre>
</div>
</div>
<p>The first time you do this, confirm that you want to connect. When asked, use the password you created in Raspberry Pi Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-weather.local
The authenticity of host 'pi-weather.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-weather.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-weather.local's password:
Linux pi-weather 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Oct 27 09:41:00 2023
&lt;username&gt;@pi-weather:~ $</code></pre>
</div>
</div>
<p>Now that you&#8217;ve connected to your Raspberry Pi, run two commands to make sure that all of your packages are up to date:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt update
$ sudo apt full-upgrade</code></pre>
</div>
</div>
<p>Once the package update commands finish running, reboot your Raspberry Pi to allow all changes to take effect:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Running this command will disconnect you from the Raspberry Pi SSH session. Wait a few seconds for your Raspberry Pi to reboot, and enter the <code>ssh</code> connection command again to reconnect to your device.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">On most terminals, press the <strong>Up</strong> arrow key, then the <strong>Enter</strong> key to re-run the most recent command.</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="connect-the-antenna-to-your-raspberry-pi">Connect the antenna to your Raspberry Pi</h2>
<div class="sectionbody">
<p>Attach the SDR dongle to any of the four available USB ports on your Raspberry Pi and attach the MCX male to BNC female adaptor into the side of the SDR. You should feel a reassuring <strong>click</strong> when the cable is inserted correctly. Attach the other end of the BNC connection to your antenna&#8217;s RG58 coax cable BNC female connector.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/pi-1024x576.jpg" alt="Raspberry Pi 4 Model B with USB SDR and MCX Male to BNC Female adaptor"></figure><figcaption><em>Raspberry Pi 4 Model B with USB SDR and MCX Male to BNC Female adaptor</em></figcaption></div>
</div>
</div>
<div class="sect1">
<h2 id="install-software">Install software</h2>
<div class="sectionbody">
<p>Now that your Raspberry Pi is up and running and your antenna is ready to use, let&#8217;s install <a href="https://github.com/jekhokie/raspberry-noaa-v2">raspberry-noaa-v2</a>. Open a terminal and run the following commands to install <code>raspberry-noaa-v2</code>.</p>
<p>First, install <a href="https://git-scm.com/">git</a>, a popular version control system:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install git -y</code></pre>
</div>
</div>
<p>Next, navigate to your home directory and use git to download <code>raspberry-noaa-v2</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ cd
$ git clone https://github.com/jekhokie/raspberry-noaa-v2.git</code></pre>
</div>
</div>
<p>Finally, open the configuration file for <code>raspberry-noaa-v2</code> with the nano text editor:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ cd raspberry-noaa-v2/
$ cp config/settings.yml.sample config/settings.yml
$ nano config/settings.yml</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="configure-raspberry-noaa-v2">Configure Raspberry NOAA V2</h3>
<p>First, configure your antenna location.</p>
<p>You can obtain your latitude and longitude coordinates from <a href="https://www.latlong.net">LatLong.net</a>, either by searching for a place name or by navigating your way around the interactive map. Find your coordinates to four decimal places (for example, <strong>52.2048, 0.1304</strong> is close enough to get you to a cracking pub in Cambridge).</p>
<p>Your altitude can be found using <a href="https://whataltitude.com/">whataltitude.com</a>. Replace <code>0.0</code> with your altitude in metres.</p>
<p>Change the default values in the configuration file to match your location:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python"># base station configurations
#   latitude: south values are negative
#   longitude: west values are negative
latitude: 52.2048
longitude: 0.1304
altitude: 42.0</code></pre>
</div>
</div>
<p>Next, configure your time zone.</p>
<p>You can use <a href="https://en.wikipedia.org/wiki/Time_zone">Wikipedia</a> to find your UTC offset.</p>
<p>Change the default values in the configuration file to match your time zone:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python"># time zone offset from UTC (for example, '-5' for US Eastern)
timezone_offset: -5</code></pre>
</div>
</div>
<p>Next, update the rest of the locale settings.</p>
<p>Visit <a href="https://www.php.net/manual/en/timezones.php">php.net/manual/en/timezones.php</a>, click on the link for your region, and find your nearest time zone in the list.</p>
<p>Choose a preferred language from the <a href="https://github.com/jekhokie/raspberry-noaa-v2/tree/master/webpanel/App/Lang">options provided by Raspberry NOAA V2</a>.</p>
<p>Change the default time zone and language values to match your time zone and preferred language:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python"># locale settings for timezone and language
#   timezone: see https://www.php.net/manual/en/timezones.php
#   lang_setting: see the 'webpanel/App/Lang' folder for available
#* * * *  languages (2-letter filename - e.g. ar, bg, de, en, es, nl)
timezone: America/New_York
lang_setting: en</code></pre>
</div>
</div>
<p>Finally, update the web server name setting.</p>
<p>We chose <code>pi-weather</code> as our hostname, so we should update the web server name value to match that hostname:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">web_server_name: pi-weather.local
enable_non_tls: false
web_port: 80
enable_tls: true
web_tls_port: 443
cert_valid_days: 365
lock_admin_page: false
admin_username: 'admin'
admin_password: 'admin'
web_passes_date_format: 'd/m/Y'
web_datetime_format: 'd/m/Y H:i:s'</code></pre>
</div>
</div>
<p>You can also change the date format settings to match your preferred style: the above example formats dates in the UK style.
To save your changes, press <strong>CTRL+X</strong>, then <strong>Y</strong>, then <strong>Enter</strong> to save your changes to the configuration file.</p>
<p>Now we can install and automatically start the Raspberry NOAA V2:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ./install_and_upgrade.sh</code></pre>
</div>
</div>
<p>This command could take a few minutes to run.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="use-your-receiving-station">Use your receiving station</h2>
<div class="sectionbody">
<p>Using your usual computer, open a browser session and visit <a href="https://pi-weather.local:443" class="bare">https://pi-weather.local:443</a>. You should see the Raspberry NOAA V2 web page.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">The first time you do this your browser may warn that you are visiting an insecure site. This is normal, and you can agree to proceed.</div></div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-15-at-15.25.09-1024x665.png" alt="A live view of weather satellites on the Raspberry NOAA V2 web interface"></figure></div>
<p>You will see a live view of weather satellites orbiting the planet and a list of satellites due to pass over your area.</p>
<p>To make this page easier to understand, click the <strong>eye icon</strong> in the top right corner of the screen (marked in red below) to change view options:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-15-at-15.26.44-1024x665.png" alt="Useful icons to interact with your Raspberry NOAA V2 web interface"></figure></div>
<p>Click the globe icon to the left to open up more options. Under <strong>Terrain</strong>, select <strong>None</strong> to show the globe.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-15-at-15.28.30-1024x665.png" alt="Satellite flyovers around a weather station in Cambridge on the Raspberry NOAA V2 web interface"></figure></div>
<p>Left click and move your mouse around to rotate the globe.</p>
<p>You should see satellites orbiting slowly across the planet, and a small red icon that marks the location of your ground station.</p>
<p>The list under the globe shows all of the satellites due to pass over your ground station. Greyed out lines are historic flyovers. Raspberry NOAA V2 records when a weather satellite flies over and updates the list of upcoming satellites every night.</p>
<p>Once you have received some data, navigate to the <strong>Captures</strong> tab:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-15-at-15.28.49-1024x665.png" alt="The Captures tab of the Raspberry NOAA V2 web interface"></figure></div>
<p>Here you will see a list of all satellite passes recorded. Click on any one for more details.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-15-at-15.29.55-1-1024x665.png" alt="Data collected from satellite passes in the Raspberry NOAA V2 web interface"></figure></div>
<p>Each picture represents specific data collected from a satellite pass.</p>
<p>You can click <strong>Information</strong> in the top right for more details.</p>
<p>For example, the following image shows cloud cover with enhanced emphasis on rainfall shown in bright green and yellow:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-11-at-12.44.04.png" alt="Cloud cover with rainfall emphasis in the Raspberry NOAA V2 web interface"></figure></div>
<p>And the following image shows temperature:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-11-at-12.45.13.png" alt="Temperature map in the Raspberry NOAA V2 web interface"></figure></div>
<p>Different satellites produce different quality images.</p>
<p>The following capture recorded a poor-quality image due to the antenna being indoors:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-08-11-at-12.50.58.png" alt="Poor quality image due to an indoor antenna"></figure></div>
<p>Image quality depends on many factors:</p>
<div class="ulist">
<ul>
<li>
<p>how directly a satellite passes overhead</p>
</li>
<li>
<p>antenna placement</p>
</li>
<li>
<p>configuration settings like gain</p>
</li>
</ul>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">Try experimenting with different antenna designs, receiver configurations, and software settings to improve your station&#8217;s performance. Small adjustments can significantly improve reception: for example, changing the gain setting for each satellite from 30 to 40 improved our images!</div></div>
</div>
</div>
<div class="sect1">
<h2 id="moving-forward">Moving forward</h2>
<div class="sectionbody">
<p>Enhancing your satellite-tracking skills can be a rewarding challenge. Even though this tutorial focuses on weather satellites, the principles you&#8217;ve learned apply to other satellite types, like amateur radio satellites or <a href="https://en.wikipedia.org/wiki/CubeSat">CubeSats</a>. Your weather satellite receiving station is not just a standalone project: it can help you deepen your understanding of space and technology.</p>
<p>Consider sharing your experiences and findings with the maker and amateur radio communities. Social media platforms, blog posts, and forum discussions are excellent ways to showcase your work, share ideas, and inspire others.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Build a satellite ground station with your Raspberry Pi and collect data from space.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/Antenna-scaled.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/Antenna-scaled.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Build your own Raspberry Pi flight tracker</title><link href="https://www.raspberrypi.com/tutorials/build-your-own-raspberry-pi-flight-tracker/" rel="alternate" type="text/html" title="Build your own Raspberry Pi flight tracker" /><published>2023-10-11T00:00:00+00:00</published><updated>2023-10-11T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/build-your-own-raspberry-pi-flight-tracker/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/build-your-own-raspberry-pi-flight-tracker/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>You can create all kinds of fun projects when you pair a Raspberry Pi with a low-cost USB Software Defined Radio (SDR). An SDR is essentially a radio wave receiver that can pick up signals from a variety of frequencies, including digital television, AM, FM, and DAB radio broadcasts, and <a href="https://www.raspberrypi.com/tutorials/build-your-own-weather-satellite-receiving-statio/">weather satellite data</a>.</p>
<p>This tutorial focuses on the information transmitted by the transponders installed on aircraft flying overhead using Automatic Dependent Surveillance – Broadcast (ADS-B). These avionic systems provide identity and altitude information to Air Traffic Control systems on the ground and Traffic Collision Avoidance Systems on other aircraft. Listen in for insight into a world we all take for granted.</p>
<p>As part of this tutorial, you&#8217;ll team up with other aviation enthusiasts and contribute to Flightradar24, who operate the world&#8217;s largest network of ADS-B/Mode S receivers. This network, together with government air traffic control and other data sources, tracks aircraft around the globe.</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>suitable Raspberry Pi power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the power supply documentation for details</a>)</p>
</li>
<li>
<p>microSD card</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>USB ADS-B receiver dongle</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up as a flight tracker.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi">Choose the right Raspberry Pi</h3>
<p>This project will work on any Raspberry Pi Model 3 or newer. For this tutorial, we&#8217;ll use a <a href="https://www.raspberrypi.com/products/raspberry-pi-3-model-a-plus/">Raspberry Pi 3 Model A+</a>.</p>
</div>
<div class="sect2">
<h3 id="choose-the-right-ads-b-receiver">Choose the right ADS-B receiver</h3>
<p>For the USB ADS-B receiver you can buy any RTL2832/R820T2-based USB dongle that&#8217;s available to you locally or from your favourite online retailer. Prices usually start around $20. This tutorial uses <a href="https://www.amazon.co.uk/NooElec-NESDR-Mini-Previously-Compatible/dp/B009U7WZCA/">NESDR Mini (TV28T v2) USB RTL-SDR, DVB-T &amp; ADS-B Receiver Set</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="install-the-pi24-operating-system">Install the Pi24 operating system</h2>
<div class="sectionbody">
<p>Download a pre-prepared Raspberry Pi operating system image from <a href="http://flightradar24.com/build-your-own">flightradar24.com</a> by clicking on the blue "Download Pi24" button:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/flightradar-download-pi24.png" alt="Downloading Pi24 from the flightradar website"></figure></div>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>There are other ADS-B services that offer similar custom OS packages, e.g. <a href="https://uk.flightaware.com/adsb/piaware/build">FlightAware</a>, <a href="https://www.adsbexchange.com/how-to-feed/adsbx-custom-pi-image/">ADS-B Exchange</a>, and <a href="https://www.radarbox.com/raspberry-pi/guide">RadarBox</a>, that will let you build an ADS-B ground station. We picked one here for the tutorial, but if you want to use one of the others, the procedure looks very similar. After installation you can also customise your installation to feed all of these services from a single Raspberry Pi.</p></div></div>
<p>Next, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Use custom</strong> and choose the <code>fr24-raspberry-pi-latest.zip</code> file you just downloaded.</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-flighttracker</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you’ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
</ul>
</div>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so you can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard and mouse.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the hostname you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi&#8217;s IP address instead.</p>
<p>For more information about finding your IP address and remote accessing your Raspberry Pi, see <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">the remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-via-ssh">Connect via SSH</h3>
<p>Open a terminal session on <em>your usual computer</em>. To access your Raspberry Pi via SSH, run the following command, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-flighttracker.local</code></pre>
</div>
</div>
<p>The first time you do this, confirm that you want to connect. When asked, use the password you created in Raspberry Pi Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-flighttracker.local
The authenticity of host 'pi-flighttracker.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-flighttracker.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-flighttracker.local's password:
Linux pi-flighttracker 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Oct 26 09:41:00 2023
&lt;username&gt;@pi-flighttracker:~ $</code></pre>
</div>
</div>
<p>Now that you&#8217;ve connected to your Raspberry Pi, run two commands to make sure that all of your packages are up to date:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt update
$ sudo apt full-upgrade</code></pre>
</div>
</div>
<p>Once the package update commands finish running, reboot your Raspberry Pi to allow all changes to take effect:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Running this command will disconnect you from the Raspberry Pi SSH session. Wait a few seconds for your Raspberry Pi to reboot, and enter the <code>ssh</code> connection command again to reconnect to your device.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">On most terminals, press the <strong>Up</strong> arrow key, then the <strong>Enter</strong> key to re-run the most recent command.</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="set-up-flightradar24">Set up Flightradar24</h2>
<div class="sectionbody">
<p>The first step is to create an account with <a href="https://www.flightradar24.com/premium/signup?utm_source=website&amp;utm_medium=nav&amp;utm_campaign=create_account">Flightradar24</a> using your email address and a password of your choice:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-06-at-10.09.16.png" alt="Create an account with Flightradar24"></figure></div>
<p>Power down your Raspberry Pi.</p>
<p>Next, connect your USB ADS-B receiver dongle to a USB port on your Raspberry Pi. Connect the antenna by plugging it into the side of the dongle. You will feel a slight reassuring click when you attach it correctly:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/DSC00108-scaled.jpg" alt="Connecting the ADS-B receiver"></figure></div>
<p>Power up your Raspberry Pi once more. SSH back into your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-flighttracker.local</code></pre>
</div>
</div>
<p>To set up the flight tracker monitor, run the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo bash -c "$(wget -O - https://repo-feed.flightradar24.com/install_fr24_rpi.sh)"</code></pre>
</div>
</div>
<p>After a brief period of setup, a welcome screen and some instructions will appear, followed by the first in a series of configuration steps:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-text" data-lang="text">Welcome to the FR24 Decoder/Feeder sign up wizard!

Before you continue please make sure that:

 1 - Your ADS-B receiver is connected to this computer or is accessible over network
 2 - You know your antenna's latitude/longitude up to 4 decimal points and the altitude in feet
 3 - You have a working email address that will be used to contact you
 4 - fr24feed service is stopped. If not, please run: sudo systemctl stop fr24feed

To terminate - press Ctrl+C at any point

Step 1.1 - Enter your email address (username@domain.tld)</code></pre>
</div>
</div>
<p>In order to continue, specify the location of your equipment.</p>
<p>You can obtain your latitude and longitude coordinates from <a href="https://www.latlong.net">LatLong.net</a>, either by searching for a place name or by navigating your way around the interactive map. Find your coordinates to four decimal places (for example, <strong>52.2048, 0.1304</strong> is close enough to get you to a cracking pub in Cambridge):</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-06-at-13.30.41.png" alt="Finding your latitude and longitude"></figure></div>
<p>You can obtain your altitude from <a href="https://whataltitude.com/">whataltitude.com</a>. If you&#8217;re using this site for the first time, you might be prompted to enable location services for your browser to access your geographical position:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-06-at-13.38.53.png" alt="Finding your altitude"></figure></div>
<p>Now it&#8217;s time to finish the FR24 wizard. Enter the email address that you used to register your Flightradar24 account:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">Step 1.2 - If you used to feed FR24 with ADS-B data before, enter your sharing key.
If you don't remember your sharing key, you can find it in your account on the website under "My data sharing".
https:&amp;#47;&amp;#47;www.flightradar24.com/account/data-sharing

Otherwise leave this field empty and continue.
$:</code></pre>
</div>
</div>
<p>Leave <strong>Step 1.2</strong> blank, as we have not used the service before, and move on.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">Step 1.3 - Would you like to participate in MLAT calculations? (yes/no)$:</code></pre>
</div>
</div>
<p>MLAT, or multilateration, refers to the process of determining an aircraft&#8217;s position and heading by analysing the time difference between the arrival of radio signals from the aircraft. Since ADS-B transponders are not fitted on all aircraft, particularly older planes, Flightradar24 calculates aircraft positions using data from three or more other community receivers. For this tutorial we will participate, so we will answer <strong>yes</strong> to proceed.</p>
<p>Next, enter the latitude, longitude, and altitude details you just looked up:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-text" data-lang="text">Step 3.A - Enter antenna's latitude (DD.DDDD)
$:52.XXXX

Step 3.B - Enter antenna's longitude (DDD.DDDD)
$:0.XXXX

Step 3.C - Enter antenna's altitude above the sea level (in feet)
$:39

Using latitude: 52.XXXX, longitude: 0.XXXX, altitude: 39ft above sea level

Validating email/location information...OK

The closest airport found is ICAO:EGSC IATA:CBG near Cambridge.

Latitude: 52.205002
Longitude: 0.175000
Country: United Kingdom

Flightradar24 may, if needed, use your email address to contact you regarding your data feed.

Would you like to continue using these settings?

Enter your choice (yes/no)$:yes</code></pre>
</div>
</div>
<p>The wizard will show the details for the nearest airport to you, followed by a final request to confirm your settings. Enter <strong>yes</strong> to continue.</p>
<p>Next, you need to confirm what type of receiver hardware you are using. In this tutorial we need to select <strong>1 - DVBT Stick (USB)</strong>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">Step 4.1 - Receiver selection (in order to run MLAT please use DVB-T stick with dump1090 utility bundled with fr24feed):

 1 - DVBT Stick (USB)
 -----------------------------------------------------
 2 - SBS1/SBS1er (USB/Network)
 3 - SBS3 (USB/Network)
 4 - ModeS Beast (USB/Network)
 5 - AVR Compatible (DVBT over network, etc)
 6 - microADSB (USB/Network)

Enter your receiver type (1-7)$</code></pre>
</div>
</div>
<p>The remaining setup steps relate to more advanced functionality, so we&#8217;ll skip over them in order to get up and running with a basic setup.</p>
<div class="ulist">
<ul>
<li>
<p>In <strong>Step 4.3</strong>, you can provide additional <code>dump1090</code> arguments describing how the data received by your device is processed. Leave this empty.</p>
</li>
<li>
<p>For <strong>Steps 5.1</strong> and <strong>5.2</strong>, which relate to exporting data from the device to another device or program, answer <strong>no</strong>.</p>
</li>
<li>
<p><strong>Step 6</strong> allows the creation of log files. Disable this by entering <strong>0</strong>.</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">Enter your receiver type (1-7)$:1
Checking for dump1090...FOUND

Step 4.3 - Enter your additional dump1090 arguments or leave empty
$:

Step 5.1 - Would you like to enable RAW data feed on port 30002 (yes/no)$:no

Step 5.2 - Would you like to enable Basestation data feed on port 30003 (yes/no)$:no

Step 6 - Please select desired logfile mode:
 0 -  Disabled
 1 -  48 hour, 24h rotation
 2 -  72 hour, 24h rotation
Select logfile mode (0-2)$:0</code></pre>
</div>
</div>
<p>Next, the wizard will submit your form data and register your device:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">Submitting form data...OK

Congratulations! You are now registered and ready to share ADS-B data with Flightradar24.
+ Your sharing key (00013e5bf0d25b8d) has been configured and emailed to you for backup purposes.
+ Your radar id is T-EGTC8, please include it in all email communication with us.
+ Please make sure to start sharing data within one month from now as otherwise your ID/KEY will be deleted.

Thank you for supporting Flightradar24! We hope that you will enjoy our Premium services that will be available to you when you become an active feeder.

To start sending data now please execute:
sudo systemctl start fr24feed

Saving settings to /etc/fr24feed.ini...OK
Installation and configuration completed!</code></pre>
</div>
</div>
<p>Congratulations, you now have a working flight tracker. Make a note of your sharing key and radar id.</p>
</div>
</div>
<div class="sect1">
<h2 id="view-aircraft-tracking-data">View aircraft tracking data</h2>
<div class="sectionbody">
<p>The magic of this project is now happening behind the scenes: your receiver is now sending data. For now, just make sure your antenna is near a window with a view of the sky.</p>
<p>The Flightradar24 operating system image for Raspberry Pi has a very convenient built-in web server; that is to say, it will host a small web page on your local network for you to see all the information your flight tracker collects. To access this information, visit <a href="http://pi-flighttracker.local/dump1090/gmap.html">pi-flighttracker.local/dump1090/gmap.html</a>.</p>
<p>Press <strong>Enter</strong> and you will see a live view of the data being collected. Click on individual aircraft for more information about each one:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-07-at-12.24.48.png" alt="Live data view of airplanes from your receiver"></figure></div>
<p>So that&#8217;s what your device is currently doing. Visit <a href="https://www.flightradar24.com">flightradar24.com</a> and log into your account to see information from all of the receivers in your area:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-07-at-10.17.56-2.png" alt="Live data view of airplanes from all nearby receivers"></figure></div>
<p>There&#8217;s a lot to take in here, so we are going to simplify things and display only the aircraft that your device is currently picking up. To do this, click on the <strong>Filters</strong> icon (circled above) at the bottom of your screen. This will bring up a window with the option to <strong>ADD FILTER</strong>. Use the slide bar to scroll down and select <strong>Radar</strong>:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-07-at-10.34.47.png" alt="Adding filters to make the live data view more manageable"></figure></div>
<p>Type in the radar id of your receiver — the one you made a note of earlier — into the box beneath the filter type:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-07-at-10.39.29.png" alt="Entering your receiver's ID"></figure></div>
<p>Finally, click on the blue <strong>New filter</strong> button. The page should show fewer aircraft; these aircraft are the ones currently tracked by your receiver:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-07-at-10.43.58.png" alt="Aircraft filtered to only those tracked by your receiver"></figure></div>
<p>Try clicking on individual aircraft and digging into the information, including origin and destination details, type of aircraft, route taken, altitude, and much more. If it&#8217;s that time of year, keep an eye out for a certain bearded and red suit-wearing fella with his reindeer; he&#8217;ll be up there somewhere.</p>
</div>
</div>
<div class="sect1">
<h2 id="onward-and-upward">Onward and upward</h2>
<div class="sectionbody">
<p>To dive deeper, think about antenna placement for better reception. Try placing your antenna outside or in an elevated position to see how many more aircraft you can pick up.</p>
<p>Building on this project might take you on a journey to more complex systems with better antennas, or perhaps a solar-powered receiving station. The sky&#8217;s the limit!</p>
<p>&#8230;&#8203;unless of course the sky isn&#8217;t your thing and you&#8217;re more interested in the sea, in which case you might want to look into receivers for Automatic Identification System transponders capable of listening to information about ocean-going vessels.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Receive signals from aircraft transponders and track flights with a Raspberry Pi 3 A+ and a low-cost USB Software Defined Radio.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/Babbage-800x533.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/Babbage-800x533.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to set up a UK train time display</title><link href="https://www.raspberrypi.com/tutorials/train-timetable-raspberry-pi-tutorial/" rel="alternate" type="text/html" title="How to set up a UK train time display" /><published>2023-10-10T00:00:00+00:00</published><updated>2023-10-10T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/train-timetable-raspberry-pi-tutorial/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/train-timetable-raspberry-pi-tutorial/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Do you hate to be late? Travel of any kind can be unpredictable, and UK trains in particular are notoriously unreliable. This tutorial helps you keep abreast of local train departures for your area of the UK in real time using a Raspberry Pi and a monitor of your choice.</p>
<p>Behind the scenes, this uses a Raspberry Pi feature called <strong>kiosk mode</strong>. Kiosk mode boots your Raspberry Pi into a full-screen web page or application <em>without using the desktop environment</em>. It&#8217;s the foundation for many different projects dedicated to information display.</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>suitable Raspberry Pi power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the power supply documentation for details</a>)</p>
</li>
<li>
<p>microSD card (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">the SD card documentation for details</a>)</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>monitor</p>
</li>
<li>
<p>display cable to connect your Raspberry Pi to your monitor (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#display">the display documentation for details</a>)</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-a-raspberry-pi">Choose a Raspberry Pi</h3>
<p>This project can run on any Raspberry Pi computer. For this tutorial, we&#8217;ll be using a <a href="https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/">Raspberry Pi Zero 2 W</a>, which has plenty of power to display train times on a monitor.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS (32-bit)</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-traintimes</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
</ul>
</div>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard and mouse. It&#8217;s perfect if your Raspberry Pi is located in a hard-to-reach location, like behind a train times display.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the hostname you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi&#8217;s IP address instead.</p>
<p>For more information about finding your IP address and remote accessing your Raspberry Pi, see <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">the remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-via-ssh">Connect via SSH</h3>
<p>Open a terminal session on <em>your usual computer</em>. To access your Raspberry Pi via SSH, run the following command, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-traintimes.local</code></pre>
</div>
</div>
<p>The first time you do this, confirm that you want to connect. When asked, use the password you created in Raspberry Pi Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-traintimes.local
The authenticity of host 'pi-traintimes.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-traintimes.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-traintimes.local's password:
Linux pi-traintimes 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Oct 24 09:41:00 2023
&lt;username&gt;@pi-traintimes:~ $</code></pre>
</div>
</div>
<p>Now that you&#8217;ve connected to your Raspberry Pi, run two commands to make sure that all of your packages are up to date:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt update
$ sudo apt full-upgrade</code></pre>
</div>
</div>
<p>Once the package update commands finish running, reboot your Raspberry Pi to allow all changes to take effect:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Running this command will disconnect you from the Raspberry Pi SSH session. Wait a few seconds for your Raspberry Pi to reboot, and enter the <code>ssh</code> connection command again to reconnect to your device.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">On most terminals, press the <strong>Up</strong> arrow key, then the <strong>Enter</strong> key to re-run the most recent command.</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-train-times-display">Configure your train times display</h2>
<div class="sectionbody">
<p>In the next section, we&#8217;ll get your train time display up and running.</p>
<div class="sect2">
<h3 id="find-your-local-train-station">Find your local train station</h3>
<p>All UK train stations have a unique code. You can find the code for your nearest (or favourite ) station at <a href="https://www.nationalrail.co.uk/stations_destinations/48541.aspx">the National Rail website</a>. For this tutorial we&#8217;ll use <code>CBG</code>: Cambridge station.</p>
<p>To find the code for your station, see <a href="https://en.wikipedia.org/wiki/UK_railway_stations">Wikipedia&#8217;s list of UK rail stations</a>.
Then, open a web browser on any device and enter the following URL, replacing the <code>CBG</code> at the end with the code for your station:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell" data-lang="shell">http://realtime.nationalrail.co.uk/ldbcis/departures.aspx?u=039B1CD1-14D4-4CB9-83B1-A84CC3AEDF83&amp;crs=CBG</code></pre>
</div>
</div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-05-19-at-09.04.35-1024x665.png" alt="The train times display provided by national rail"></figure></div>
<p>You should now see the real-time departure board for your station. Notice that your browser has added a query parameter, <code>H</code>, at the end of the URL. Look for <code>&amp;H=</code>, followed by a number. This scales the page based on your monitor&#8217;s resolution.</p>
<p><strong>Make a note of the <code>H</code> query parameter value</strong> — you&#8217;ll use it later on to scale the display for your Raspberry Pi&#8217;s monitor.</p>
</div>
<div class="sect2">
<h3 id="configure-kiosk-mode">Configure kiosk mode</h3>
<p>To make a usable display of train times, we need to configure our Raspberry Pi to start up the train times web page in <strong>kiosk mode</strong>. Kiosk mode hides the browser chrome to display just the web page on your display. We also need to disable the screensaver and DPMS (Display Power Management Signalling) so the train times display doesn&#8217;t turn off on its own without interaction.</p>
<p>Next, we need to write the contents of <code>.config/wayfire.ini</code>. Run the following command to use the nano text editor to make changes to the file:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano .config/wayfire.ini</code></pre>
</div>
</div>
<p>Take a look at the section titled <code>[autostart]</code>. At the moment, it reads like this:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">[autostart]
panel = wfrespawn wf-panel-pi
background = wfrespawn pcmanfm --desktop --profile LXDE-pi
xdg-autostart = lxsession-xdg-autostart</code></pre>
</div>
</div>
<p>Let&#8217;s append a few lines to this section to automatically start kiosk mode whenever your Raspberry Pi powers on:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">chromium = chromium-browser "https://realtime.nationalrail.co.uk/ldbcis/departures.aspx?u=039B1CD1-14D4-4CB9-83B1-A84CC3AEDF83&amp;crs=CBG&amp;H=1440" --kiosk --noerrdialogs --disable-infobars --no-first-run --ozone-platform=wayland --enable-features=OverlayScrollbar --start-maximized
screensaver = false
dpms = false</code></pre>
</div>
</div>
<p>Add to the file directly below the existing contents of the <code>[autostart]</code> section. <strong>Remember to update the <code>CBG</code> station code to your own station code, and to include the <code>H</code> query parameter value you noted before!</strong> When you finish, you should end up with the following:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">[autostart]
panel = wfrespawn wf-panel-pi
background = wfrespawn pcmanfm --desktop --profile LXDE-pi
xdg-autostart = lxsession-xdg-autostart
chromium = chromium-browser "https://realtime.nationalrail.co.uk/ldbcis/departures.aspx?u=039B1CD1-14D4-4CB9-83B1-A84CC3AEDF83&amp;crs=CBG&amp;H=1440" --kiosk --noerrdialogs --disable-infobars --no-first-run --ozone-platform=wayland --enable-features=OverlayScrollbar --start-maximized
screensaver = false
dpms = false</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with <code>nano</code>.
Next, reboot your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Now, check the monitor attached to your Raspberry Pi. It should display the train information in full screen mode. Now you&#8217;re ready to set your train timetable up wherever it can make your life easier&#8201;&#8212;&#8201;by your front door, at your desk at work, or possibly at your local train station.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="moving-forward">Moving forward</h2>
<div class="sectionbody">
<p>Why not check out our <a href="https://www.raspberrypi.com/tutorials/how-to-use-a-raspberry-pi-in-kiosk-mode/">kiosk mode</a> tutorial, which goes into more detail about kiosk mode and keeping your Raspberry Pi secure when left unattended?</p>
<p>Or perhaps try your hand at what might be the ultimate in kiosk mode projects: <a href="https://www.raspberrypi.com/tutorials/how-to-build-a-super-slim-smart-mirror/">How to build a super slim smart mirror</a>.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[View local UK train departures in real time using a Raspberry Pi and your monitor of choice.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/Train-timetable-800x533.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/Train-timetable-800x533.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to build a super-slim smart mirror</title><link href="https://www.raspberrypi.com/tutorials/how-to-build-a-super-slim-smart-mirror/" rel="alternate" type="text/html" title="How to build a super-slim smart mirror" /><published>2023-07-10T00:00:00+00:00</published><updated>2023-07-10T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/how-to-build-a-super-slim-smart-mirror/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/how-to-build-a-super-slim-smart-mirror/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Smart mirrors, or magic mirrors as they&#8217;re often called, have been around for several years and are nearly always near the top of any maker&#8217;s would-love-to-do list. Their popularity and appeal hasn&#8217;t declined with time, and the idea of performing your morning ablutions in front of a mirror that displays your day&#8217;s schedule, monitors your home&#8217;s systems, and offers up a cheeky joke still sounds a bit like a scene out of a sci-fi movie.</p>
<p>Early smart mirrors often removed a bulky computer monitor from its housing, which entailed dealing with power and wiring issues. So a smart mirror required comfort with with high-voltage electricity and DIY skills to make a custom frame.</p>
<p>Happily, display technology has advanced. Now is an excellent time to build a smart mirror with low-voltage, ultra-slim displays. We&#8217;ll build one into a frameless modern design using standard-sized parts and materials in order to minimise the DIY requirement. Combine that with the power, size, and form factor of Raspberry Pi 3A+, and you have yourself a magic recipe.</p>
</div>
</div>
<div class="sect1">
<h2 id="how-does-it-work">How does it work?</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/mr-bean-mirror.jpeg" alt="Mr Bean under police interrogation behind a two-way mirror"></figure><figcaption><em>Mr Bean under police interrogation behind a two-way mirror</em></figcaption></div>
<p>Smart mirrors display an image on a screen mounted behind a two-way mirror that allows a small amount of light to pass through. This allows you to see the display while still retaining the reflective properties of a mirror.</p>
<p>This project uses a Raspberry Pi 3A+ connected to a disassembled ultra-thin 15.6-inch 1080p USB-C-powered monitor. Everything is mounted behind a specially manufactured piece of pre-cut A3-sized acrylic mirror.</p>
<p>Additional tools and craft skills will be kept to an absolute bare minimum to make this project as uncomplicated as possible, but we will still produce a sleek and modern-looking smart mirror.</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">Where we haven&#8217;t linked to a particular product for an item in this list, we&#8217;ve given its specification in such a way that copying and pasting it into the search box of your favourite online retailer should help you locate what you need.</div></div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.raspberrypi.com/products/raspberry-pi-3-model-a-plus/">Raspberry Pi 3 Model A+</a></p>
</li>
<li>
<p>suitable Raspberry Pi power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the power supply documentation for details</a>)</p>
</li>
<li>
<p>microSD card</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>portable slim 15.6" HDMI USB-C-powered monitor (such as <a href="https://www.amazon.co.uk/AILRINNI-Portable-Monitor-Built-Speakers/dp/B0B1D3NN41">this one</a>)</p>
</li>
<li>
<p>USB-C power supply for the display</p>
</li>
<li>
<p>Mini HDMI male to standard HDMI cable, 15cm (with 90 degree connector for display)</p>
</li>
<li>
<p>8 × M3 15mm + 6mm male-to-female thread nylon hexagon standoff (spacer) pillars</p>
</li>
<li>
<p>8 × M3 10mm Phillips round head nylon machine bolts, black</p>
</li>
<li>
<p>8 × M3 nylon machine nuts, black</p>
</li>
<li>
<p>A3-sized piece of black card</p>
</li>
<li>
<p>VHB double-sided heavy-duty foam tape</p>
</li>
<li>
<p>A3-sized 2mm thick clear acrylic (plexiglass) sheet (such as <a href="https://www.amazon.co.uk/gp/product/B093KTCKCN">this one</a>)</p>
</li>
<li>
<p>A3-sized 3mm thick two-way acrylic mirror sheet (such as <a href="https://www.cutplasticsheeting.co.uk/">this one</a>)</p>
</li>
<li>
<p>50mm duct tape</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up as a smart mirror.</p>
</li>
</ul>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner"><p>The nylon spacers, nuts, and bolts listed above often come cheaper in kits, such as the one available <a href="https://www.amazon.co.uk/Zocipro-Standoff-Lightweight-Motherboard-Assortment/dp/B09FXPX6PX">here</a>.</p></div></div>
<div class="sect2">
<h3 id="tools-required">Tools required</h3>
<div class="ulist">
<ul>
<li>
<p>electric drill</p>
</li>
<li>
<p>3mm drill bit</p>
</li>
<li>
<p>craft knife and metal ruler (for cutting card sheet)</p>
</li>
<li>
<p>small Phillips head screwdriver</p>
</li>
<li>
<p>prying tool (used to disassemble monitor)</p>
</li>
<li>
<p>(optional) 3D-printed drill bit alignment jig – STL files available for free at <a href="https://www.printables.com/model/344643-3mm-drill-bit-alignment-jig">printables.com/344643-3mm-drill-bit-alignment-jig</a>.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi">Choose the right Raspberry Pi</h3>
<p>This project works with all models of Raspberry Pi, but in order to maintain the intended slim look of our mirror we will use a Raspberry Pi 3 Model A+. If you decide to use a <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi 4</a>, you&#8217;ll need slightly larger M3 20mm standoffs to accommodate the larger board.</p>
</div>
<div class="sect2">
<h3 id="choose-the-right-power-supply">Choose the right power supply</h3>
<p>This project will require two power supplies: one for your Raspberry Pi, plus a USB-C power supply for the display itself. You can also use a single power supply that splits to provide both micro USB and USB-C connectors such as <a href="https://www.amazon.co.uk/gp/product/B07MYYSYFC/">this one</a>. If you choose this option, ensure that your power supply can provide sufficient power to both devices.</p>
</div>
<div class="sect2">
<h3 id="choose-the-right-hdmi-cable">Choose the right HDMI cable</h3>
<p>The 90-degree angle in your HDMI cable should lie flat against the monitor when connected, as demonstrated in the photo below:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_2250-2-500x375.png" alt="A 90 degree angled HDMI cable"></figure></div>
</div>
<div class="sect2">
<h3 id="choose-the-right-display">Choose the right display</h3>
<p>The higher the contrast between light and dark, the better your smart mirror will look. When reviewing specifications for a suitable display, pay particular attention to its brightness, which you&#8217;ll find specified in units that might be unfamiliar to you: <strong>nits</strong> and <strong>cd/m<sup>2</sup></strong>. Cd/m<sup>2</sup> (<em>candelas per square metre</em>) is a unit that derives from a very old brightness metric based on whale oil candles. Nit derives from the Latin word "nitere", "to shine". Conveniently, 1 nit is equal to 1 cd/m<sup>2</sup>.</p>
<p>Look for a bright display: no less than 300 nits (or cd/m<sup>2</sup>).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS (32-bit)</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-mirror</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
</ul>
</div>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard and mouse. It&#8217;s perfect if your Raspberry Pi is located in a hard-to-reach location, like behind a train times display.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the hostname you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi&#8217;s IP address instead.</p>
<p>For more information about finding your IP address and remote accessing your Raspberry Pi, see <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">the remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-to-your-raspberry-pi-via-ssh">Connect to your Raspberry Pi via SSH</h3>
<p>Open a terminal session on your usual computer and run the following to access your Raspberry Pi via SSH, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-mirror.local</code></pre>
</div>
</div>
<p>The first time you do this, confirm that you want to connect. When asked, use the password you created in Raspberry Pi Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-mirror.local
The authenticity of host 'pi-mirror.local (2a00:23c8:3880:d801:34e0:2052:bc72:dd67)' can't be established.
ED25519 key fingerprint is SHA256:NjLggsBZzj6N99rABupQCwyhjNnGpeMT6T9jaoRShu8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-mirror.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-mirror.local's password:
Linux pi-mirror 5.15.32-v7l+ #1538 SMP Thu Mar 31 19:39:41 BST 2022 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Oct 26 09:41:00 2023
&lt;username&gt;@pi-mirror:~ $</code></pre>
</div>
</div>
<p>Now that you&#8217;ve connected to your Raspberry Pi, run two commands to make sure that all of your packages are up to date:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt update
$ sudo apt full-upgrade</code></pre>
</div>
</div>
<p>Once the package update commands finish running, reboot your Raspberry Pi to allow all changes to take effect:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Running this command will disconnect you from the Raspberry Pi SSH session. Wait a few seconds for your Raspberry Pi to reboot, and enter the <code>ssh</code> connection command again to reconnect to your device.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">On most terminals, press the <strong>Up</strong> arrow key, then the <strong>Enter</strong> key to re-run the most recent command.</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="construct-your-smart-mirror-hardware">Construct your smart mirror hardware</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="disassemble-your-display">Disassemble your display</h3>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/DSC00001-800x450.png" alt="A display"></figure></div>
<p>First, prepare your display. Separate it from the housing into component parts. The display we&#8217;ve used for this tutorial is fairly generic and is often branded with different names. It comes apart with relative ease and is made up of only a metal front display bezel, a metal rear housing, a driver board, a control board, and two speakers. We need to remove the metal front display bezel which is held in place only by a small amount of glue:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/screen_1-800x450.jpg" alt="Insert a prying tool behind the display bezel"></figure></div>
<p>With a prying tool, prise the screen away from the bezel and pull the frame away from the screen. You may find it useful to heat the frame gently with a hairdryer in order to loosen the glue holding it in place:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/screen2-800x450.jpg" alt="Pull away the bezel to access the screen beneath"></figure></div>
<p>As soon as you have enough space to get between the bezel and the screen, gently pull the bezel away until it is completely separated. You may need to use the hairdryer again to heat the frame to help the process along:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/screen3-800x450.jpg" alt="The housing interior"></figure></div>
<p>Once you have removed the frame, fold back the screen gently to reveal the contents of the rear housing. You&#8217;ll see two circuit boards: a larger driver board and a smaller controller board. Be sure not to pull out any of the wires and flexes connecting everything; take particular care when handling the screen, as it will be connected to the driver board by a delicate ribbon cable. Again, it&#8217;s just glue holding the driver and control boards in place. They can be removed from the housing by heating and prying as we did earlier for the front display bezel:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/speakers-800x450.jpg" alt="Remove two Phillips head screws from each speaker to detach them from the housing"></figure></div>
<p>Detach the two flat speakers from the housing by removing two small Phillips head screws from each one. Finally, remove any pieces of tape that are holding cables in place. Set aside your display ready to install into your smart mirror later in the tutorial.</p>
</div>
<div class="sect2">
<h3 id="prepare-to-assemble-your-smart-mirror">Prepare to assemble your smart mirror</h3>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-01-13-at-10.38.38.png" alt="From left to right"></figure></div>
<p>Let&#8217;s take a moment to review the final assembly before we begin some of the construction steps. As the illustration above shows from left to right, there are:</p>
<div class="ulist">
<ul>
<li>
<p>an A3-sized 2mm thick clear acrylic back plate</p>
</li>
<li>
<p>the disassembled display with the driver, control boards, and Raspberry Pi</p>
</li>
<li>
<p>a piece of A3-sized black card with a display-sized hole cut from its centre</p>
</li>
<li>
<p>an A3-sized 3mm thick acrylic two-way mirror</p>
</li>
</ul>
</div>
<p>The nylon nuts, bolts, and spacers hold all of these pieces together to form our smart mirror.
The design of this smart mirror does not require any sawing or cutting of acrylic pieces, or even any frame-making skills whatsoever. To assemble the mirror:</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Drill eight mounting holes.</p>
</li>
<li>
<p>Make a cutout in the middle of the black card for the display.</p>
</li>
<li>
<p>Mount the Raspberry Pi and display components to the back of the display.</p>
</li>
<li>
<p>Secure all the pieces together.</p>
</li>
</ol>
</div>
<p>The following sections walk you through these steps in greater detail.</p>
</div>
<div class="sect2">
<h3 id="drill-the-mounting-holes">Drill the mounting holes</h3>
<p>We need to make eight mounting holes in perfectly matching locations through the A3-sized acrylic and card pieces. The easiest way to do this is to drill through all three pieces at the same time into a suitable flat surface, such as a piece of engineered wood, using a general-purpose drill bit (any drill bit other than a masonry bit should work). Prepare the clear acrylic piece, black card, and two-way mirror for drilling by holding them together in alignment. Drill eight 3mm holes exactly 15mm in from the edges of the pieces, at each of the four corners and at the midway points down each of the sides, as shown in the diagram below:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-21-at-13.23.45-copy-800x573.png" alt="Drilling guide"></figure><figcaption><em>Drilling guide</em></figcaption></div>
<p>If you have a 3D printer, you can print our <a href="https://www.printables.com/model/344643-3mm-drill-bit-alignment-jig">alignment jigs</a> to simplify things. You can also measure with a ruler and mark out where holes should be drilled. In order to avoid unnecessary scratches, we recommend keeping the protective covering on your acrylic pieces throughout the entire process:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_2080-800x600.jpg" alt="3D printed corner drill alignment jig"></figure><figcaption><em>3D printed corner drill alignment jig</em></figcaption></div>
</div>
<div class="sect2">
<h3 id="mount-the-display-to-the-card">Mount the display to the card</h3>
<p>The display you are using is very unlikely to be exactly A3 in size, so we will give it a black border. This prevents light from passing through the back of the two-way mirror around the display and spoiling the overall effect. Measure your display area. With a craft knife and a metal ruler, cut out an area 1-2mm smaller than your measurements in the center of your A3 black card:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-12-21-at-13.48.23-800x541.png" alt="Cutting a display cut-out from the A3 black card"></figure></div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">Make your cut-out a little smaller than the display itself to make it easier to mount the display.</div></div>
</div>
<div class="sect2">
<h3 id="mount-the-electronic-parts-to-the-display">Mount the electronic parts to the display</h3>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/DSC00131-800x450.jpg" alt="Mounting components with double-sided heavy-duty foam tape"></figure></div>
<p>Cover the back of the display with a single layer of 50mm duct tape. This serves two purposes: firstly providing a protective isolation layer between the printed circuit boards and the display, and secondly improving the appearance of the mirror.</p>
<p>Add pieces of VHB double-sided heavy-duty foam tape to the backs of the driver, control, and Raspberry Pi boards, as well as to the two speakers. Attach each of these to the back of the display such that their ports are still accessible from the edge.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">You might need to use the display control board to adjust brightness and contrast in your finished build, so if possible you should mount this board such that its controls remain fairly accessible from the edge too.</div></div>
<p>Next, attach the display to your black card border using duct tape:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_2069-800x600.jpg" alt="Attach the display to the black card with duct tape"></figure></div>
<p>Flip everything over to get a preview of the seamless display effect:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_2073-800x450.jpg" alt="A display perfectly centered within an A3 black card frame"></figure></div>
</div>
<div class="sect2">
<h3 id="final-hardware-assembly">Final hardware assembly</h3>
<p>Connect display control board and and your Raspberry Pi with the mini HDMI to HDMI cable.</p>
<p>Connect the power cables (or single split power cable) for the display and Raspberry Pi.</p>
<p>Now we can now assemble the smart mirror using nuts, bolts, and spacers.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">We suggest nylon rather than metal fasteners to avoid accidental cracking of the acrylic if overtightened.</div></div>
<p>For each of the eight holes:</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>push a bolt from the front of the mirror and through the black card border</p>
</li>
<li>
<p>screw it into a spacer</p>
</li>
<li>
<p>fit the matching hole in the back panel over the other end of the spacer</p>
</li>
<li>
<p>tighten a nut onto the spacer</p>
</li>
</ol>
</div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-01-13-at-10.23.34-800x372.png" alt="Assemble the smart mirror with nuts"></figure></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="program-your-smart-mirror">Program your smart mirror</h2>
<div class="sectionbody">
<p>To program the smart mirror, we&#8217;ll run a form of <a href="https://www.raspberrypi.com/tutorials/how-to-use-a-raspberry-pi-in-kiosk-mode/">kiosk mode</a> on your Raspberry Pi. This allows you to boot directly into a full-screen application without interacting with the computer. Kiosk mode is the foundation for a wide variety of projects that display information. Airports, shops, hospitals, cafes, and museums all use kiosk devices to provide information or services like timetables, waiting times, product information, directions, self-check-in machines, and more.</p>
<p>In this tutorial, we&#8217;ll set up our smart mirror with <a href="https://magicmirror.builders/">Magic Mirror<sup>2</sup></a>.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner">The Raspberry Pi community chose this software as the winner of <a href="https://magpi.raspberrypi.com/">The MagPi</a> magazine&#8217;s <a href="https://magpi.raspberrypi.com/issues/50">50th issue</a> celebration feature.</div></div>
<p>Power up your Raspberry Pi and display.</p>
<p>You should see the desktop environment on the display through the two-way mirror. For the best possible viewing experience:</p>
<div class="ulist">
<ul>
<li>
<p>use the display&#8217;s native control panel to adjust the brightness and contrast to their maximum values</p>
</li>
<li>
<p>disable any power-saving mode to prevent the display from dimming</p>
</li>
</ul>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">Depending on where you stuck the display control board on the back of the display, you may have to use an implement, such as a pen, to access the controls.</div></div>
<div class="sect2">
<h3 id="set-the-display-orientation">Set the display orientation</h3>
<p>Connect with SSH, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-mirror.local</code></pre>
</div>
</div>
<p>By default, your desktop will display in landscape orientation. If this is your preference, move on to the installation of <a href="https://magicmirror.builders/">Magic Mirror<sup>2</sup></a>. To use your mirror in portrait orientation, we can turn the desktop by editing <code>.config/wayfire.inh</code>. Use the following command to open this file in your preferred text editor, in our case nano:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano .config/wayfire.ini</code></pre>
</div>
</div>
<p>Add the following lines to the end of the file so it reads as follows:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">[output]
transform=90</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with <code>nano</code>.</p>
<p>Reboot the Raspberry Pi to activate your changes:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>When your device reboots, the desktop should display in portrait mode. Connect over SSH again to continue.</p>
<div class="sect3">
<h4 id="install-the-magic-mirror2-software">Install the Magic Mirror<sup>2</sup> software</h4>
<p>First, we&#8217;ll install Node.js, the open source server environment program used as the basis for this smart mirror project. Run the following two commands to install Node.js:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
$ sudo apt install -y nodejs</code></pre>
</div>
</div>
<p>Next, install a package manager for JavaScript. Run the following command to install Node Package Manager, the default for Node.js:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install npm</code></pre>
</div>
</div>
<p>Run the following commands to download the Magic Mirror repository, enter the directory, and install Magic Mirror:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ git clone https://github.com/MichMich/MagicMirror
$ cd MagicMirror
$ npm run install-mm</code></pre>
</div>
</div>
<p>Copy over the sample configuration file to use it as a template for our display:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ cp config/config.js.sample config/config.js</code></pre>
</div>
</div>
<p>Finally, start the application with the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ npm run start</code></pre>
</div>
</div>
<p>Wait a minute or so, and you should see the default Magic Mirror display. It should look like this:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-01-05-at-10.53.24-800x1207.png" alt="The default Magic Mirror display"></figure><figcaption><em>Thanks, smart mirror!</em></figcaption></div>
<p>The Magic Mirror software will now display a sample mirror based on the configuration file we copied over a couple of steps earlier. This file specifies what, when, and how to display information on your screen. The default configuration displays a number of modules, including time, date, weather, US holidays, a news feed, and a compliments module. You can adjust, add, and remove modules to your liking.</p>
<p>Since the amazing <a href="https://michaelteeuw.nl/">Michael Teeuw</a> created the original magic mirror, a community of enthusiasts has created hundreds of modules. One lets you know when your local refuse collector is coming. Another keeps you up-to-date on the newest online cat videos. If you can&#8217;t find one you like, write your own! The great thing about a project like this is that you can personalise it to suit your specific requirements.</p>
</div>
</div>
<div class="sect2">
<h3 id="automatically-start-your-magic-mirror-using-pm2">Automatically start your Magic Mirror using PM2</h3>
<p>We need to finish one more step before we can customise our mirror. Magic Mirror currently starts and stops manually from the command line over SSH. We&#8217;ll add an autostart program that also gives you a few extra features you might find useful.</p>
<p>Before we begin, stop Magic Mirror by pressing <strong>Ctrl+C</strong>.</p>
<p>PM2 is a process manager for Node.js applications like Magic Mirror. With PM2, we can start, stop, maintain, and interact with Magic Mirror. Install PM2 with the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo npm install -g pm2</code></pre>
</div>
</div>
<p>To use PM2, we&#8217;ll have to start it after every boot. Luckily, there&#8217;s built-in help for this. Execute the following command to set up autostart for PM2:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ pm2 startup</code></pre>
</div>
</div>
<p>After a short introduction, this should output a command that will automatically start PM2 after boot.</p>
<p>Copy and run the command provided by the response.</p>
<p>Next, create a small bash script that starts Magic Mirror:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano ~/mm.sh</code></pre>
</div>
</div>
<p>Type or paste the following code into it:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">cd ./MagicMirror
DISPLAY=:0 npm start</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with <code>nano</code>.</p>
<p>Enter the following command to make the file executable:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo chmod +x ~/mm.sh</code></pre>
</div>
</div>
<p>Now, use PM2 to run your new bash script that start the Magic Mirror application with the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ pm2 start mm.sh</code></pre>
</div>
</div>
<p>The mirror will display exactly as it did before, but PM2 controls the process now.</p>
<p>PM2 autostarts programs it controls from saved state.</p>
<p>Run the following command to save PM2&#8217;s current state:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ pm2 save</code></pre>
</div>
</div>
<p>If your Raspberry Pi loses power, PM2 will autostart when your Raspberry Pi is powered up again.
PM2 will restore the most recently saved state. And the smart mirror will automatically start working.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="personalise-your-magic-mirror">Personalise your Magic Mirror</h2>
<div class="sectionbody">
<p>To begin our journey to a fully customised mirror, we will modify an existing module to meet our needs.</p>
<div class="sect2">
<h3 id="the-magic-mirror-configuration-file">The Magic Mirror configuration file</h3>
<p>Since the <code>config.js</code> file is where some of the magic happens, let&#8217;s take a closer look at it:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano MagicMirror/config/config.js</code></pre>
</div>
</div>
<p>The file is written in <a href="https://en.wikipedia.org/wiki/JavaScript">JavaScript</a>.</p>
<p>Press <strong>CTRL+X</strong> to exit nano without making any changes. Whenever you make a successful change to your config.js file, type the following to make a backup:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo cp MagicMirror/config/config.js MagicMirror/config/config.jsBACKUP</code></pre>
</div>
</div>
<p>Since we&#8217;ve given the backup file the made-up filename extension <code>.jsBACKUP</code>, the system will ignore it. But if you make a change to <code>config.js</code> that causes an error and you&#8217;re unable to fix it, you can replace your broken <code>config.js</code> file with your functional <code>config.jsBACKUP</code> file with the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo cp MagicMirror/config/config.jsBACKUP MagicMirror/config/config.js</code></pre>
</div>
</div>
<p>These backups can help you keep track of changes to your smart mirror configuration over time. Consider adding a number or a date after "BACKUP" in the commands above to keep multiple backup files as you tweak your configuration over time.</p>
<p>Backups are especially handy when you see this dreaded error screen:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-01-09-at-12.36.52-800x409.png" alt="The dreaded Magic Mirror error screen"></figure></div>
</div>
<div class="sect2">
<h3 id="configure-an-existing-module">Configure an existing module</h3>
<p>Edit your <code>config.js</code> file to modify one of the modules that appear on our mirror.</p>
<p>The last module in the file is the news feed module, which pulls news from an RSS feed — a way of distributing content updates from a website in a concise format.</p>
<p>Open your configuration file in nano:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano ~/MagicMirror/config/config.js</code></pre>
</div>
</div>
<p>For this tutorial, we&#8217;ll add two feeds: one for Raspberry Pi Tutorials, and one that provides news local to Pi Towers. Once we&#8217;ve done that, the bottom of our file will look like this:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">    {
      module: "newsfeed",
      position: "bottom_bar",
      config: {
        feeds: [
          {
            title: "Raspberry Pi Tutorials",
            url: "https://www.raspberrypi.com/tutorials/feed"
          },
          {
            title: "Cambridge Independent News",
            url: "https://www.cambridgeindependent.co.uk/_api/rss/cambridge_independent_news_feed.xml"
          }
        ],
        showSourceTitle: true,
        showPublishDate: true,
        broadcastNewsFeeds: true,
        broadcastNewsUpdates: true
      }
    },
  ]
};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}</code></pre>
</div>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">You can add additional RSS feeds by adding additional entries to the <code>feeds</code> list. Don&#8217;t forget to separate the feed entries with a comma!</div></div>
<p>Once you are happy with the changes you&#8217;ve made to the file, press <strong>CTRL+X</strong>, then <strong>Y</strong>, then <strong>Enter</strong>. Then, type the restart command for the Magic Mirror application to see the result:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ pm2 restart mm</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="remove-modules">Remove modules</h3>
<p>Edit your <code>config.js</code> file to remove one of the modules that appear on our mirror.</p>
<p>We&#8217;ll remove the weather module, which appears in the top right corner of our screen. It&#8217;s made up of two small modules, one for the current weather and one for a forecast. Here at Cambridge UK it&#8217;s always sunny, so we don&#8217;t need this weather forecast.</p>
<p>Open your configuration file in nano:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano ~/MagicMirror/config/config.js</code></pre>
</div>
</div>
<p>Delete this entire section from the config file, removing everything from the first open curly bracket to the last closing curly bracket and comma:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">{
  module: "weather",
  position: "top_right",
  config: {
    weatherProvider: "openweathermap",
    type: "current",
    location: "New York",
    locationID: "5128581", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your c&gt;
    apiKey: "YOUR_OPENWEATHER_API_KEY"
  }
},
{
  module: "weather",
  position: "top_right",
  header: "Weather Forecast",
  config: {
    weatherProvider: "openweathermap",
    type: "forecast",
    location: "New York",
    locationID: "5128581", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your c&gt;
    apiKey: "YOUR_OPENWEATHER_API_KEY"
  }
},</code></pre>
</div>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">You might have noticed that these modules weren&#8217;t working properly anyway, due to a requirement for a valid API key and location ID number. An API key is a unique identifier that&#8217;s used to authenticate data requests from one computer to another, in this case a request from your Raspberry Pi for a weather forecast from <a href="https://openweathermap.org/api">openweathermap.org</a>. Explore that webpage for further information, including location IDs and how to get an API key, if you want to keep this module.</div></div>
<p>Once you are happy with the changes you&#8217;ve made to the file, press <strong>CTRL+X</strong>, then <strong>Y</strong>, then <strong>Enter</strong>. Then, type the restart command for the Magic Mirror application to see the result:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ pm2 restart mm</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="add-new-modules">Add new modules</h3>
<p>Adding a new module involves two steps:</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Install the module.</p>
</li>
<li>
<p>Modify <code>config.js</code> again use the module.</p>
</li>
</ol>
</div>
<p>There are plenty of <a href="https://forum.magicmirror.builders/category/7/showcase">modules to choose from</a>, but we&#8217;re going with one that will display an image of our choice where the weather modules used to be. This particular module is called <a href="https://github.com/mykle1/MMM-EasyPix">MMM-EasyPix</a> and was made by <a href="https://github.com/mykle1">Mykle</a>.</p>
<p>To begin, download MMM-EasyPix into the <code>modules</code> folder:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ cd ~/MagicMirror/modules/
$ git clone https://github.com/mykle1/MMM-EasyPix</code></pre>
</div>
</div>
<p>Next, modify <code>config.js</code> to use the module.</p>
<p>Open your configuration file in nano:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano ~/MagicMirror/config/config.js</code></pre>
</div>
</div>
<p>Paste the following sample MMM-EasyPix configuration into the list of modules:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">{
  module: "MMM-EasyPix",
  position: "top_right",
  config: {
    picName: "grid.jpg",     // Enter the picture file name.
    maxWidth: "100%",        // Size picture precisely. Retains aspect ratio.
  }
},</code></pre>
</div>
</div>
<p>The code above calls the MMM-EasyPix module and assigns the following parameters:</p>
<div class="ulist">
<ul>
<li>
<p>positions the picture in the top right corner of our display where the weather modules used to be</p>
</li>
<li>
<p>names the picture we want to show (in this case <code>grid.jpg</code>, one of several demo images preloaded with the module and found in the folder <code>~/MagicMirror/modules/MMM-EasyPix/pix</code>)</p>
</li>
<li>
<p>sizes the image</p>
</li>
</ul>
</div>
<p>Once you are happy with the changes you&#8217;ve made to the file, press <strong>CTRL+X</strong>, then <strong>Y</strong>, then <strong>Enter</strong>. Then, type the restart command for the Magic Mirror application to see the result:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ pm2 restart mm</code></pre>
</div>
</div>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner"><p>To position a module, select from the following list. Enter the position as a new value for the <code>position</code> field:</p>
<div class="ulist">
<ul>
<li>
<p><code>top_bar</code></p>
</li>
<li>
<p><code>bottom_bar</code></p>
</li>
<li>
<p><code>top_left</code></p>
</li>
<li>
<p><code>bottom_left</code></p>
</li>
<li>
<p><code>top_center</code></p>
</li>
<li>
<p><code>bottom_center</code></p>
</li>
<li>
<p><code>top_right</code></p>
</li>
<li>
<p><code>bottom_right</code></p>
</li>
<li>
<p><code>upper_third</code></p>
</li>
<li>
<p><code>middle_center</code></p>
</li>
<li>
<p><code>lower_third</code></p>
</li>
</ul>
</div></div></div>
<p>You should now see a new image on the display:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-01-09-at-10.29.56-800x423.png" alt="The smart mirror displays an image instead of the weather"></figure></div>
<p>Let&#8217;s replace that image with the Raspberry Pi logo.</p>
<p>Fetch the image from the internet:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">curl https://upload.wikimedia.org/wikipedia/en/c/cb/Raspberry_Pi_Logo.svg -o ~/MagicMirror/modules/MMM-EasyPix/pix/logo.svg</code></pre>
</div>
</div>
<p>Finally, edit the <code>config.js</code> file again to change <code>grid.jpg</code> to our <code>logo.svg</code> image file.</p>
<p>Open your configuration file in nano:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano ~/MagicMirror/config/config.js</code></pre>
</div>
</div>
<p>Paste the following sample MMM-EasyPix configuration into the list of modules:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">{
  module: "MMM-EasyPix",
  position: "top_right",
  config: {
    picName: "logo.svg",     // Enter the picture file name.
    maxWidth: "100%",        // Size picture precisely. Retains aspect ratio.
  }
},</code></pre>
</div>
</div>
<p>Once you are happy with the changes you&#8217;ve made to the file, press <strong>CTRL+X</strong>, then <strong>Y</strong>, then <strong>Enter</strong>. Then, type the restart command for the Magic Mirror application to see the result:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ pm2 restart mm</code></pre>
</div>
</div>
<p>Congratulations! You&#8217;re ready to go off on your own to build the best smart mirror you can imagine.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2023-01-09-at-11.44.05-800x1224.png" alt="The smart mirror displays a Raspberry Pi logo"></figure></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="extend-the-project">Extend the project</h2>
<div class="sectionbody">
<p>Start by checking out more of the wide variety of modules made by the <a href="https://forum.magicmirror.builders/category/7/showcase">community</a> you&#8217;re now a part of.</p>
<p>A favourite of ours is <a href="https://github.com/Jopyth/MMM-Remote-Control">MMM-Remote-Control</a>, which allows users to control their mirror via a web browser from any smart phone or tablet. This frees you from SSH on the command line, replacing it with a graphical interface.</p>
<p>Because we have retained the speakers and their connections from the original screen and used the Raspberry Pi HDMI connection, you can play audio. There are plenty of possibilities for audio-related modules, like a smart speaker or an online radio player.</p>
<p>With the addition of a camera and microphone, you could create a voice-activated smart mirror with facial recognition, and integrate it with smart home features you may already have.</p>
<p>Perhaps you have an idea that no one else has considered yet, which may lead you to <a href="https://docs.magicmirror.builders/development/introduction.html">develop your own module</a>. The chance to make sci-fi a reality awaits you!</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[A smart mirror is a dream project for a lot of makers. Our step-by-step tutorial brings this impressive build within reach.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/MAGIC-MIRROR-800x533.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/MAGIC-MIRROR-800x533.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to control your 3D printer using OctoPrint and Raspberry Pi</title><link href="https://www.raspberrypi.com/tutorials/set-up-raspberry-pi-octoprint/" rel="alternate" type="text/html" title="How to control your 3D printer using OctoPrint and Raspberry Pi" /><published>2023-01-10T00:00:00+00:00</published><updated>2023-01-10T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/set-up-raspberry-pi-octoprint/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/set-up-raspberry-pi-octoprint/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Control and manage your 3D printer and more using OctoPrint and Raspberry Pi. Here&#8217;s everything you need to know to get started!</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>suitable power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the documentation for details</a>)</p>
</li>
<li>
<p>microSD card (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">the documentation for details</a>)</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>USB cable (check your 3D printer for details)</p>
</li>
<li>
<p>Raspberry Pi camera or USB webcam (optional)</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-a-raspberry-pi">Choose a Raspberry Pi</h3>
<p>OctoPrint supports older Raspberry Pi devices, but this tutorial uses a 2GB <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi 4 Model B</a> for a faster, smoother experience.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Other specific purpose OS &gt; 3D printing &gt; OctoPi (stable)</strong>.</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>octopi</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
</ul>
</div>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="set-up-your-raspberry-pi">Set up your Raspberry Pi</h2>
<div class="sectionbody">
<p>Connect your 3D printer to your Raspberry Pi using the appropriate USB cable for your printer. For this tutorial, we&#8217;re using an Ender 5, which requires a USB-A-to-mini-USB cable.</p>
</div>
</div>
<div class="sect1">
<h2 id="set-up-octoprint">Set up OctoPrint</h2>
<div class="sectionbody">
<p>Open a web browser on <em>your usual computer</em>. Type <a href="http://octopi.local" class="bare">http://octopi.local</a> into the address bar. This will allow you to set up OctoPrint. Follow the on-screen instructions to set up OctoPrint and enter details for your 3D printer. Once complete, OctoPrint will restart and you&#8217;ll be able to get printing by following the on-screen instructions.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/OctoPrint_SetUp_1-800x620.png" alt="The OctoPrint setup wizard"></figure></div>
<p>You can access OctoPrint at any time by visiting <a href="http://octopi.local" class="bare">http://octopi.local</a> on a computer or mobile device connected to the same network as your Raspberry Pi.</p>
<div class="sect2">
<h3 id="add-a-camera-optional">Add a camera (optional)</h3>
<p>To keep an eye on your models as they print, add a Raspberry Pi camera or a USB webcam.</p>
<p>To do this:</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Unplug your Raspberry Pi from the power supply</p>
</li>
<li>
<p>Connect your Raspberry Pi camera or webcam</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/raspberry-pi-camera-octoprint-800x501.png" alt="A Raspberry Pi with connected Raspberry Pi camera"></figure></div>
</li>
<li>
<p>Reconnect the power supply and open OctoPrint at <a href="http://octopi.local" class="bare">http://octopi.local</a></p>
</li>
<li>
<p>Click the wrench icon to enter the OctoPrint Settings menu</p>
</li>
<li>
<p>Under <strong>FEATURES</strong>, select <strong>Webcam Timelapse</strong></p>
</li>
</ol>
</div>
<p>Here, you can click the <strong>Test</strong> button to make sure your camera works properly and make any necessary changes, such as altering aspect ratio and rotation.</p>
<p>You can also enable time-lapse recordings of your prints and save them to your Raspberry Pi.</p>
<p>You can view your camera settings under <strong>Control</strong> on the main OctoPrint dashboard.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="using-octoprint">Using OctoPrint</h2>
<div class="sectionbody">
<p>OctoPrint offers a dashboard that meets the needs of most users. More advanced users may want to investigate the third-party plugins managed by the community. You can find them in the OctoPrint Settings menu.</p>
<p>OctoPrint is a free-to-download open-source web interface created and maintained by <a href="https://twitter.com/foosel">Gina Häußge</a>. If you would like to support OctoPrint, you can make a contribution <a href="https://octoprint.org/">via their website</a>.</p>
</div>
</div>
<div class="sect1">
<h2 id="help-and-support">Help and support</h2>
<div class="sectionbody">
<p>More help and information on OctoPrint is available from their <a href="https://octoprint.org/">website</a> and <a href="https://community.octoprint.org/">forums</a>.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Control and manage your 3D printer and more using OctoPrint and Raspberry Pi.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/octoprint-raspberrypi-tutorial-800x533.png" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/octoprint-raspberrypi-tutorial-800x533.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to play retro games on your Raspberry Pi with RetroPie</title><link href="https://www.raspberrypi.com/tutorials/retropie-raspberry-pi-tutorial/" rel="alternate" type="text/html" title="How to play retro games on your Raspberry Pi with RetroPie" /><published>2022-12-25T00:00:00+00:00</published><updated>2022-12-25T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/retropie-raspberry-pi-tutorial/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/retropie-raspberry-pi-tutorial/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Are you looking to (re)discover the joy of playing retro video games using a Raspberry Pi and RetroPie? Here&#8217;s everything you need to know to get started!</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>suitable Raspberry Pi power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the power supply documentation for details</a>)</p>
</li>
<li>
<p>microSD card (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">the SD card documentation for details</a>)</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>display cable to connect your Raspberry Pi to your monitor (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#display">the display documentation for details</a>)</p>
</li>
<li>
<p>monitor</p>
</li>
<li>
<p>USB flash drive</p>
</li>
<li>
<p>USB gaming controller</p>
</li>
</ul>
</div>
<p>For the initial SD card setup and to add games to your RetroPie, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up for retro gaming.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi">Choose the right Raspberry Pi</h3>
<p>Although RetroPie will work on any Raspberry Pi, even the $5 <a href="https://www.raspberrypi.com/products/raspberry-pi-zero/">Raspberry Pi Zero</a>, we recommend using one with as much RAM as possible. More RAM means a smoother gaming experience. For this tutorial, we&#8217;ll be using an 8GB <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi 4</a>.</p>
<p><a href="https://www.raspberrypi.com/products/raspberry-pi-400/">Raspberry Pi 400</a> is also a great choice, especially if some of your favourites use the keyboard as a controller.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Emulation and game OS &gt; RetroPie</strong> and select the appropriate image for your Raspberry Pi model.</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>retropi</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
</ul>
</div>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="plug-in-your-gaming-controller">Plug in your gaming controller</h3>
<p>We&#8217;re using a generic USB gaming controller, but you can also use a variety of wired console controllers such as those made for Xbox and PlayStation. If you plan on using a wireless gaming controller that doesn&#8217;t have its own dongle, be prepared to troubleshoot some connection issues.</p>
<div class="admonitionblock tip" role="note"><h5 class="label">tip</h5><div class="inner">For more information about connecting a gaming controller, see <a href="https://retropie.org.uk/docs/Xbox-360-Controller/">the RetroPie controller documentation</a>.</div></div>
</div>
<div class="sect2">
<h3 id="configure-your-gaming-controller">Configure your gaming controller</h3>
<p>RetroPie should now begin its initial start up process. When prompted, follow the on-screen instructions to configure your controller. When complete, press your newly assigned <strong>A</strong> button to exit the setup.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="add-games-to-retropie">Add games to RetroPie</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="format-your-usb-flash-drive-using-your-usual-computer">Format your USB flash drive using your usual computer</h3>
<p>You&#8217;ll need to format your USB flash drive to FAT32 or exFAT before you use it to move your games to your Raspberry Pi. You can format it on macOS using the Disk Utility application, or on Windows by right-clicking on the flash drive then selecting <strong>Format</strong>.</p>
</div>
<div class="sect2">
<h3 id="build-your-folders">Build your folders</h3>
<p>Next, create a new folder on your USB flash drive and name it <code>retropie</code>. Eject the flash drive from your usual computer and plug it into your Raspberry Pi. RetroPie will now create folders on the USB flash drive for you. This should only take a few minutes. You&#8217;ll know it&#8217;s complete when the LED on your Raspberry Pi stops blinking.</p>
</div>
<div class="sect2">
<h3 id="download-roms">Download ROMS</h3>
<p>Game files are called <em>ROMs</em>. You can download them from a variety of online sources. There are a few copyright restrictions surrounding ROMs; always check that the website you&#8217;re using does not supply pirated content. Websites like <a href="https://itch.io/">itch.io</a> provide some brilliant homebrew ROMs, and you can also find some official SEGA ROMs on <a href="https://store.steampowered.com/">Steam</a>.</p>
</div>
<div class="sect2">
<h3 id="transfer-your-roms-to-retropie">Transfer your ROMs to RetroPie</h3>
<p>Remove the USB flash drive from your Raspberry Pi and plug it back into your usual computer. You&#8217;ll now see a vast array of folders on the drive, named after all your favourite consoles, in <code>/retropie/roms</code>. It&#8217;s now time to drop your ROMs into their respective folders and eject the USB flash drive again.</p>
<p>Plug the USB flash drive back into your Raspberry Pi once more and wait for the LED to stop blinking. The transfer time depends on how many ROMs you&#8217;re transferring, so don&#8217;t worry if it takes a while. We recommend using this time to make yourself a nice cup of tea.</p>
<p>Eject the USB flash drive, then restart your Raspberry Pi by selecting <strong>Start</strong> on your controller, followed by <strong>Quit</strong>, and then <strong>RestartEmulationStation</strong>.</p>
<p>Once your Raspberry Pi restarts, you&#8217;ll find all your games uploaded and ready to play.</p>
<p>You can repeat the download and transfer process to add more ROMs to your Raspberry Pi at any time without losing your existing games.</p>
<p>Happy playing!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="some-of-our-favourite-retropie-diy-consoles">Some of our favourite RetroPie DIY consoles</h2>
<div class="sectionbody">
<p>Makers across the world have used Raspberry Pi and RetroPie to build arcade systems and homebrew handheld consoles to play their favourite games. Here are some of our favourites:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/llJMTF8-500x333-1.jpeg" alt="A cool Raspberry Pi retro machine build"></figure></div>
<div class="dlist">
<dl>
<dt class="hdlist1"><a href="https://www.raspberrypi.com/news/fiveish-awesome-retropie-builds/">Five(ish) awesome RetroPie builds</a></dt>
<dd>
<p>Five of what we believe to be some of the best RetroPie builds shared on social media.</p>
</dd>
</dl>
</div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/gamebox-comparison-500x375-1.jpeg" alt="A GameBoy Raspberry Pi build"></figure></div>
<div class="dlist">
<dl>
<dt class="hdlist1"><a href="https://www.raspberrypi.com/news/game-boy-zero/">GameBoy Zero</a></dt>
<dd>
<p>We see a lot of Raspberry Pi Zero retro gaming mods, but we think this one might just take the biscuit.</p>
</dd>
</dl>
</div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/mtk1ztc2ymug-500x375-1.jpeg" alt="An entire RetroPie setup contained in a NES cartridge"></figure></div>
<div class="dlist">
<dl>
<dt class="hdlist1"><a href="https://www.raspberrypi.com/news/pi-cart-retropie-in-a-nes-cartridge/">Pi Cart: RetroPie in a NES Cartridge</a></dt>
<dd>
<p>Using a Raspberry Pi Zero, it&#8217;s fairly easy to create your own Cart at minimal cost!</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect1">
<h2 id="retro-gaming-with-raspberry-pi">Retro Gaming with Raspberry Pi</h2>
<div class="sectionbody">
<p>The MagPi magazine has put together a 164-page guide with everything you need to know about retro gaming with Raspberry Pi. You can <a href="https://magpi.raspberrypi.com/books/retro-gaming">download a free PDF</a> from The MagPi magazine website, or find it in <a href="https://magpi.raspberrypi.com/books/retro-gaming-raspberry-pi-2nd-edition">the Bookshelf app on Raspberry Pi OS</a>.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/RetroGamingV2_1080x-800x800.jpeg" alt="The Retro Gaming with Raspberry Pi book"></figure></div>
</div>
</div>
<div class="sect1">
<h2 id="retropie">RetroPie</h2>
<div class="sectionbody">
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Retropie-Logo-500x214.png" alt="The RetroPie logo"></figure></div>
<p><a href="https://retropie.org.uk/">RetroPie</a> is free-to-download open source software built upon a variety of emulators such as EmulationStation and RetroArch. If you&#8217;d like to support the RetroPie team, you can <a href="https://retropie.org.uk/donate/">make a contribution</a> via their website.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Are you looking to (re)discover the joy of playing retro video games using a Raspberry Pi and RetroPie? Here’s everything you need to know to get started.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/RetroPie_GREY-800x532.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/RetroPie_GREY-800x532.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to add ambient lighting to your TV with Raspberry Pi</title><link href="https://www.raspberrypi.com/tutorials/raspberry-pi-tv-ambient-lighting/" rel="alternate" type="text/html" title="How to add ambient lighting to your TV with Raspberry Pi" /><published>2022-12-25T00:00:00+00:00</published><updated>2022-12-25T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/raspberry-pi-tv-ambient-lighting/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/raspberry-pi-tv-ambient-lighting/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Make watching TV more immersive: you can extend the action on screen to the surrounding environment and reduce eye-strain with Raspberry Pi-powered ambient lighting.</p>
</div>
</div>
<div class="sect1">
<h2 id="overview">Overview</h2>
<div class="sectionbody">
<p>To configure ambient lighting for your TV, you&#8217;ll need to do the following things:</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Set up your LEDs.</p>
</li>
<li>
<p>Configure a Raspberry Pi running Raspberry Pi OS.</p>
</li>
<li>
<p>Install HyperHDR to your Raspberry Pi.</p>
</li>
<li>
<p>Configure your setup for the best ambient lighting experience.</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>suitable Raspberry Pi power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the power supply documentation for details</a>)</p>
</li>
<li>
<p>microSD card (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">the SD card documentation for details</a>)</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>HDMI Capture Card (see <strong>Choose a capture card</strong> below)</p>
</li>
<li>
<p>NeoPixels LED strip (see <strong>Choose an LED strip</strong> below)</p>
</li>
<li>
<p>DC5V barrel jack AC adapter (see <strong>Choose a power supply</strong> below)</p>
</li>
<li>
<p>Female barrel jack connector</p>
</li>
<li>
<p>2x HDMI to HDMI cable</p>
</li>
<li>
<p>USB-A male to USB-A male cable</p>
</li>
<li>
<p>2x female to male jumper wire</p>
</li>
<li>
<p>Optional&#8201;&#8212;&#8201;HDMI hub (for multiple input sources; require an additional HDMI to HDMI cable)</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up as the ambient lighting controller.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi-and-accessories">Choose the right Raspberry Pi and accessories</h3>
<p>This tutorial uses a Raspberry Pi 3. We do not recommend using a Raspberry Pi Zero for this project.</p>
</div>
<div class="sect2">
<h3 id="choose-a-capture-card">Choose a capture card</h3>
<p>If you plan to watch content from streaming sites such as Netflix and Disney+, you&#8217;ll need a capture card that supports <a href="https://en.wikipedia.org/wiki/High-bandwidth_Digital_Content_Protection">HDCP</a>. Choose a capture card that matches your display resolution: for instance, if your TV has a resolution of 4K (or you might soon upgrade to a 4K tv), you&#8217;ll want a 4K capture card.</p>
</div>
<div class="sect2">
<h3 id="choose-an-led-strip">Choose an LED strip</h3>
<p>The size of your monitor dictates the length of LED strip you need to purchase. To determine the length, measure all the edges of your monitor and add them together. For example, our 47" TV measures 106cm along the top and bottom, and 62cm either side. So we&#8217;ll need at least 336cm of NeoPixels. As strips are usually sold in metres, we ordered 4m and cut off the excess.</p>
</div>
<div class="sect2">
<h3 id="choose-a-power-supply">Choose a power supply</h3>
<p>The more LEDs you have, the more power you will need. To get an approximate measure of the output you&#8217;ll need to run your LED strip, use the following equation:</p>
<p><br></p>
<div class="listingblock">
<div class="content">
<pre>0.06 x LED quantity = output current</pre>
</div>
</div>
<p><br></p>
<p>Our project uses 150 LEDs, so we&#8217;ll need approximately 9A power. As 9A isn&#8217;t a standard output current for off-the-shelf power supplies, and because we also need to power our Raspberry Pi, we&#8217;re using a 5V 10A barrel jack power supply for our setup.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS Lite (32-bit)</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-ambient</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
</ul>
</div>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard and mouse. It&#8217;s perfect if your Raspberry Pi is located in a hard-to-reach location like the back of your television.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the hostname you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi&#8217;s IP address instead.</p>
<p>For more information about finding your IP address and remote accessing your Raspberry Pi, see <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">the remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-via-ssh">Connect via SSH</h3>
<p>Open a terminal session on <em>your usual computer</em>. To access your Raspberry Pi via SSH, run the following command, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-ambient.local</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-ambient.local
The authenticity of host 'pi-ambient.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-ambient.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-ambient.local's password:
Linux pi-ambient 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Oct 24 09:41:00 2023
&lt;username&gt;@pi-ambient:~ $</code></pre>
</div>
</div>
<p>When asked for your password, use the password you created in Raspberry Pi Imager.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="install-hyperhdr">Install HyperHDR</h2>
<div class="sectionbody">
<p>We&#8217;re going to install HyperHDR, a fork of Hyperion that supports HDR. While not everyone using this tutorial will need HDR support, having this added benefit will future-proof your build with no loss of Hyperion functionality.</p>
<p>Now you&#8217;ve gained access to your Raspberry Pi, it&#8217;s best to check it&#8217;s up-to-date with the latest version of Raspberry Pi OS. To do this, run the following commands in a terminal:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt update
$ sudo apt upgrade</code></pre>
</div>
</div>
<p>Next, we need to download and install HyperHDR. HyperHDR is available for a variety of platforms. The following code will allow us to check the system and install the Raspberry Pi-specific software. Run the following script, entering Y when prompted.</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ wget https://github.com/awawa-dev/HyperHDR/releases/download/v17.0.0.0/HyperHDR-17.0.0.0-Linux-`uname -m`.deb
$ sudo apt install ./HyperHDR-17.0.0.0-Linux-`uname -m`.deb
$ sudo sed -i '/^User/d' /etc/systemd/system/hyperhdr\@.service
$ sudo systemctl daemon-reload
$ sudo service hyperhdr@pi restart
$ sudo service hyperhdr@pi status</code></pre>
</div>
</div>
<p>The above script has been slightly edited from EverythingSmartHome&#8217;s original install script to include the recent version of HyperHDR. You can find the original script at <a href="https://gist.github.com/EverythingSmartHome/e4151d7e9b7c1c953a72ddb536730c6d" class="bare">https://gist.github.com/EverythingSmartHome/e4151d7e9b7c1c953a72ddb536730c6d</a>.</p>
</div>
</div>
<div class="sect1">
<h2 id="connect-hardware">Connect hardware</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="power-your-led-strip">Power your LED strip</h3>
<p>Your LED strip should arrive pre-wired with three wires: live, ground, and data. Ideally, they&#8217;ll be pre-installed into a connector, with additional live and ground wires, which we&#8217;ll be using to power the strip.</p>
<p>These two wires will likely be red and white, or red and black. Red is live, and white/black is ground. If required, strip them to expose 0.5cm of wire</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Image-from-iOS-3-1-800x533.jpg" alt="Strip the two wires to expose half a centimetre of wire"></figure></div>
<p>Next cut the USB-A end from your microUSB/USB-C cable. Depending on the type of cable, you&#8217;ll find either two or three wires inside. Again, these represent live and ground and, in some cases, data. As with the LED strip, strip 0.5cm of the live wire (usually red), and the ground wire (usually white or black)</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Image-from-iOS-1-2-800x534.jpg" alt="Stripping the wires near the severed USB-A end of the microUSB or USB-C cable"></figure></div>
<p>Insert the live wire from the LED strip and microUSB/USB-C lead into the + hole of your female barrel jack connector and tighten them in place. Our connector uses a small screw to secure the wires. Next, insert the ground wire from the LED strip and microUSB/USB-C lead into the + hole of the connector and again tighten them into place</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Image-from-iOS-5-800x533.jpg" alt="Connecting wires to the female barrel jack connector"></figure></div>
</div>
<div class="sect2">
<h3 id="connect-your-led-strip-to-your-raspberry-pi">Connect your LED strip to your Raspberry Pi</h3>
<p>We&#8217;re going to use the GPIO pins of the Raspberry Pi to connect to the data wire of the LED strip. By default, HyperHDR is configured to connect to GPIO 18 and, though you can change this in the dashboard settings later, there&#8217;s no reason not to use GPIO 18.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/GPIO-Pinout-Diagram-2.png" alt="GPIO 18 is the sixth pin down on the right hand side of your Raspberry Pi's header pins"></figure><figcaption><em>GPIO 18 is the sixth pin down on the right hand side of your Raspberry Pi&#8217;s header pins</em></figcaption></div>
<p>You may also wish to connect a second wire between the ground wire of your LED strip and one of the GPIO ground pins to prevent your lights from flickering. For some setups, we&#8217;ve found this isn&#8217;t necessary, and for some it is. Better safe than sorry.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Image-from-iOS-2-1-800x534.jpg" alt="GPIO pins connected to GPIO 18 and a ground"></figure></div>
</div>
<div class="sect2">
<h3 id="attach-the-led-strip-to-your-tv">Attach the LED strip to your TV</h3>
<p>Next, you need to line the rear edge of your monitor with the LED strip. Try to get them as close to the edge as you can without making them visible from the front. When approaching corners, you can either:</p>
<div class="ulist">
<ul>
<li>
<p>cut your strip and solder wires to allow for the bend</p>
</li>
<li>
<p>use dedicated LED strip corner adapters</p>
</li>
<li>
<p>fold the strip as shown</p>
</li>
</ul>
</div>
<p>Folding is the easiest option, but remember to account for any 'hidden' LEDs later when we set up HyperHDR.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambient_Light_LED-800x600.png" alt="Folding the LED strip at the corners of the display"></figure></div>
<p>For ease, attach your LED in a clockwise direction when facing the monitor. If you attach them anti-clockwise, remember to select <strong>Reverse direction</strong> in the <strong>LED layout</strong> menu of HyperHDR later on in the process.</p>
<div class="sect3">
<h4 id="connect-your-input-device">Connect your input device</h4>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Connect the USB port of your capture card to a USB port of your Raspberry Pi using a USB-to-USB cable.</p>
</li>
<li>
<p>Connect the capture card&#8217;s HDMI OUT port to your monitor using an HDMI-to-HDMI lead.</p>
</li>
<li>
<p>Lastly, connect your input device (games console, DVD Player, TV receiver) to the capture card&#8217;s HDMI INPUT port using the second HDMI to HDMI lead.</p>
</li>
</ol>
</div>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambient_light_HDMI-800x600.png" alt="Connecting the capture card"></figure></div>
</div>
</div>
<div class="sect2">
<h3 id="multiple-input-devices-optional">Multiple input devices (optional)</h3>
<p>If you have more than one device you wish to input into your TV, you can use an HDMI hub. Plug all your devices into the hub and connect the hub&#8217;s HDMI OUT port to the HDMI IN port of the capture card.</p>
<p>Once everything is plugged in, connect your power supply to the barrel jack connector. Your setup is now complete. We recommend tidying up your wires and securing everything to the back of your TV or into a ventilated container.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-hyperhdr">Configure HyperHDR</h2>
<div class="sectionbody">
<p>Next, we&#8217;re going to use the HyperHDR dashboard to configure the setup for your monitor.
Open a browser window on your computer and enter your hostname into the address bar: <a href="http://pi-ambient.local:8090" class="bare">http://pi-ambient.local:8090</a></p>
<p>The HyperHDR dashboard will open in the browser window. If it does not, check your network connection and restart your Raspberry Pi.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambilight_Dashboard_1.png" alt="The HyperHDR dashboard"></figure></div>
<div class="sect2">
<h3 id="led-hardware">LED hardware</h3>
<p>Our first step is to tell HyperHDR what type of LEDs we have, and how many there are. Select <strong>LED hardware</strong> in the side menu. This should open up the <strong>LED controller</strong> menu.</p>
<p>There are many different types of LED controllers on the market. We&#8217;re using a ws2812B LED strip, as it&#8217;s a good balance between functionality and cost. So we&#8217;ll select "ws281x" from the <strong>Controller type</strong> dropdown menu.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambilight_Dashboard_2.png" alt="Configuring LED hardware on the HyperHDR dashboard"></figure></div>
<p>Once you&#8217;ve selected your controller type, you need to enter the number of LEDs on your strip in both the <strong>Hardware LED count</strong> and <strong>Maximum LED count</strong> boxes. Confirm your jumper wire is connected to GPIO 18 and that 18 is selected in the <strong>GPIO number box</strong>, then click <strong>Save settings</strong>.</p>
<p>Next, select <strong>LED layout</strong> at the top of the page.</p>
<p>Here, we need to tell HyperHDR where our LEDs are. Enter the number of LEDs for the top, bottom, and sides of your monitor into the appropriate boxes. You&#8217;ll also want to move the input indicator to the correct position. Ours is located at the bottom of our television.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambilight_Dashboard_3.png" alt="Configuring LED position on the HyperHDR dashboard"></figure></div>
<p>Ideally, you&#8217;ll have attached your LEDs in a clockwise direction. If not, now is the time to select <strong>Reverse direction</strong>.</p>
<p>Click <strong>Save layout</strong>.</p>
</div>
<div class="sect2">
<h3 id="video-capturing">Video capturing</h3>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Select <strong>Video capturing</strong> from the side menu.</p>
</li>
<li>
<p>Check <strong>USB capture &gt; Device</strong> for your capture card. If you don&#8217;t see the capture card, try restarting the Raspberry Pi and waiting a few minutes.</p>
</li>
<li>
<p>Select your capture card and save settings at the bottom of the menu.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambilight_Dashboard_4.png" alt="Configuring a capture card on the HyperHDR dashboard"></figure></div>
</li>
<li>
<p>In <strong>Instance USB capture</strong>, select <strong>Enable USB capture</strong> and save settings at the bottom of the menu.</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="image-processing">Image processing</h3>
<p>Select <strong>Image processing</strong> from the side menu.
Scroll down and activate <strong>Blackbar detection</strong> and <strong>Save settings</strong>.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambilight_Dashboard_5.png" alt="Enable Blackbar detection on the HyperHDR dashboard"></figure></div>
</div>
<div class="sect2">
<h3 id="rgb-order-wizard">RGB order wizard</h3>
<p>Lastly, we&#8217;re going to make sure HyperHDR is aware of the RGB order of your LED strip. Select <strong>Advanced</strong> from the side menu, followed by <strong>Misc</strong> and <strong>RGB order wizard</strong>. Here, you&#8217;ll need to tell HyperHDR whether the colours on the screen match the colours of your LEDs:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambilight_Dashboard_7.png" alt="Configure LED color order for nonstandard LEDs on the HyperHDR dashboard"></figure></div>
</div>
<div class="sect2">
<h3 id="finish-up">Finish up</h3>
<p>After following the steps of this tutorial, you should see your LED lights reacting to the video content on your television. If you don&#8217;t, go back and double-check the steps to ensure you followed them correctly.</p>
<p>Chances are, you&#8217;ll need to tweak the settings to get the best experience from your LEDs. We needed to move the input location a few LEDs in the <strong>LED layout</strong> section to match our lights to the images on the screen. For those of you with a taste for colour theory, HyperHDR offers a variety of more advanced options. To access them, select <strong>Advanced</strong> from the side menu, followed by <strong>Misc</strong> and <strong>Settings level</strong>. Here, you can select <strong>Expert</strong> to access all HyperHDR features in the dashboard.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Ambilight_Dashboard_6.png" alt="Configure the Expert settings level to access all HyperHDR features from the dashboard"></figure></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="help-and-support">Help and support</h2>
<div class="sectionbody">
<p>For support with Hyperion settings and issues, please visit the <a href="https://hyperion-project.org/forum/">Hyperion forums</a>.</p>
<p>For HyperHDR specific queries and to submit issues with the software, visit the <a href="https://github.com/awawa-dev/HyperHDR">HyperHDR GitHub</a> repo.</p>
<p>For support with official Raspberry Pi products, please visit the <a href="https://forums.raspberrypi.com/">Raspberry Pi Forums</a>.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Make watching TV more immersive with Raspberry Pi-powered ambient lighting.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/Ambient_Light_TV-800x501.png" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/Ambient_Light_TV-800x501.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Raspberry Pi Pico Iron Man Arc Reactor</title><link href="https://www.raspberrypi.com/tutorials/raspberry-pi-pico-iron-man-arc-reactor/" rel="alternate" type="text/html" title="Raspberry Pi Pico Iron Man Arc Reactor" /><published>2022-12-25T00:00:00+00:00</published><updated>2022-12-25T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/raspberry-pi-pico-iron-man-arc-reactor/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/raspberry-pi-pico-iron-man-arc-reactor/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>If you enjoy Raspberry Pi-based DIY build projects, there&#8217;s a good chance that Iron Man might just be one of your favourite superhero characters. A billionaire inventor who created a suit of armour powered by a small, powerful electric generator known as an Arc Reactor — what&#8217;s not to like? We&#8217;re going to build our own Arc Reactor using a strip of LEDs and some wizardry to produce a 3D infinity mirror effect.</p>
</div>
</div>
<div class="sect1">
<h2 id="how-does-it-work">How does it work?</h2>
<div class="sectionbody">
<p>In this tutorial we&#8217;ll use a Raspberry Pi Pico to control 31 individually addressable LED lights mounted between two discs of acrylic plastic. One of those discs will have a layer of adhesive mirror sheet and the other will have a one-way mirror film; this will give the LEDs a 3D infinity effect. Unfortunately, we haven&#8217;t yet perfected our own plasma fusion power source at Raspberry Pi, so instead we will use a rechargeable battery and enclose everything in a 3D-printed case.</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi <a href="https://www.raspberrypi.com/products/raspberry-pi-pico/">Pico</a></p>
</li>
<li>
<p>micro USB charging cable for Raspberry Pi Pico</p>
</li>
<li>
<p>Flexible strip of colour pixel LED lights (these tend to come in 1m lengths; we used this 144 <a href="https://shop.pimoroni.com/products/flexible-rgb-led-strip-neopixel-ws2812-sk6812-compatible?variant=30260032110675">WS2812B strip</a> and cut it down to a strip of 31 LEDs, leaving plenty left over for another project)</p>
</li>
<li>
<p>3mm thick acrylic sheet, sufficient to cut 2 x 70mm discs</p>
</li>
<li>
<p>Self-adhesive flexible mirror tile sheet (not glass)</p>
</li>
<li>
<p>One-way mirror self-adhesive film (the type used as sun-blocking window stickers)</p>
</li>
<li>
<p>USB-C 5V 1A TP4506 charging board for 18650 lithium battery (or micro USB equivalent)</p>
</li>
<li>
<p>Rechargeable 3.7V 1100mAh 603449 lithium-ion battery</p>
</li>
<li>
<p>2-position 3P SPDT panel-mount micro slide toggle switch, latching</p>
</li>
<li>
<p>Approx 100cm of 26AWG silicone stranded copper wire (or similar)</p>
</li>
<li>
<p>Quick-drying superglue</p>
</li>
<li>
<p>3D-printed enclosure parts (STL design files available for free at <a href="http://printables.com/model/278332-raspberry-pi-pico-iron-man-arc-reactor">printables.com/model/278332-raspberry-pi-pico-iron-man-arc-reactor</a>)</p>
</li>
</ul>
</div>
<p>This list will help you locate everything you need from your favourite online retailer.</p>
<p>As part of the initial setup, you will also need:</p>
<div class="ulist">
<ul>
<li>
<p>A computer, a micro USB cable, and soldering equipment and supplies (soldering in this project is minimal: no need to worry if you are not proficient at soldering!)</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="install-firmware">Install firmware</h2>
<div class="sectionbody">
<p>To begin, flash the Pico with firmware using the drag-and-drop method to transfer files. This works just like transferring files to a USB memory stick.</p>
<p>On your computer, download the UF2 file for the latest release of the Pico MicroPython firmware from <a href="https://micropython.org/download/rp2-pico/">micropython.org/download/rp2-pico/</a>. The MicroPython programming language is an implementation of Python optimised for use with microcontrollers.</p>
<p>To copy the UF2 file you&#8217;ve just downloaded over to your Pico, you need to put it into bootloader mode. Hold down the <strong>BOOTSEL</strong> button (the small button next to the USB port) while simultaneously plugging a micro USB cable connected to your Pico into your usual computer. Your Pico should now show up as a drive called <strong>RPI-RP2</strong>:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-10.13.38-800x425.png" alt="The RPI-RP2 drive on macOS Finder"></figure><figcaption><em>The RPI-RP2 drive on macOS Finder</em></figcaption></div>
<p>Drag and drop the <code>.uf2</code> firmware file that you just downloaded into the <strong>RPI-RP2</strong> drive. Your Pico will now reboot automatically. Once you&#8217;ve done this, the next time you plug in your Pico, it won&#8217;t show up as a drive. But leave the Pico connected for now.</p>
</div>
</div>
<div class="sect1">
<h2 id="program-your-pico">Program your Pico</h2>
<div class="sectionbody">
<p>Download, install, and open <a href="https://thonny.org/">Thonny</a>, a Python IDE (Integrated Development Environment). It&#8217;s the software you&#8217;ll use on your computer to program your Pico. With your Pico still connected, Thonny should look like this:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-15.33.42.png" alt="Programming a Pico with Thonny"></figure></div>
<p>If you see <code>&gt;&gt;&gt;</code> in the Shell window, then you&#8217;re already connected to your Pico and have an interactive session enabled. This means you&#8217;re ready to program your Pico.</p>
<p>If you don&#8217;t see <code>&gt;&gt;&gt;</code> in the Shell window, check that Thonny is set up correctly:</p>
<div class="ulist">
<ul>
<li>
<p>Click on the text in the very bottom right corner of the Thonny window. Check that the <strong>MicroPython (Raspberry Pi Pico)</strong> interpreter is selected. If anything else is selected, choose <strong>MicroPython (Raspberry Pi Pico)</strong> from the list.</p>
</li>
<li>
<p>If for some reason you weren&#8217;t successful in flashing the firmware, Thonny may prompt you to install it at this stage. If Thonny prompts you to do this, repeat the <strong>Install firmware</strong> step.</p>
</li>
<li>
<p>If you still don&#8217;t see <code>&gt;&gt;&gt;</code> in the Shell window, disconnect and reconnect your Pico. Then, press the red <strong>STOP</strong> sign in Thonny&#8217;s top menu bar to reset everything.</p>
</li>
</ul>
</div>
<p>Now you&#8217;re ready to program your Pico. Copy and paste the following into the empty <strong>&lt;untitled&gt;</strong> Thonny program window:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">import array, time
from machine import Pin
import rp2

# Configure the number of WS2812 LEDs.
NUM_LEDS = 31
PIN_NUM = 28
brightness = 1

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)
[T3 - 1]
    jmp(not_x, "do_zero")   .side(1)
[T1 - 1]
    jmp("bitloop")          .side(1)
[T2 - 1]
    label("do_zero")
    nop()                   .side(0)
[T2 - 1]
    wrap()# Create the StateMachine with the ws2812 program, outputting on pin
sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(PIN_NUM))

# Start the StateMachine, it will wait for data on its FIFO.
sm.active(1)

# Display a pattern on the LEDs via an array of LED RGB values.
ar = array.array("I",
[0 for _ in range(NUM_LEDS)])

##########################################################################
def pixels_show():
    dimmer_ar = array.array("I",
[0 for _ in range(NUM_LEDS)])
    for i,c in enumerate(ar):
        r = int(((c &gt;&gt; 8)
&amp; 0xFF) * brightness)
        g = int(((c &gt;&gt; 16)
&amp; 0xFF) * brightness)
        b = int((c
&amp; 0xFF) * brightness)
        dimmer_ar
[i] = (g&lt;&lt;16) + (r&lt;&lt;8) + b
    sm.put(dimmer_ar, 8)
    time.sleep_ms(10)

def pixels_set(i, color):
    ar
[i] = (color
[1]&lt;&lt;16) + (color
[0]&lt;&lt;8) + color
[2]

def pixels_fill(color):
    for i in range(len(ar)):
        pixels_set(i, color)

def color_chase(color, wait):
    for i in range(NUM_LEDS):
        pixels_set(i, color)
        time.sleep(wait)
        pixels_show()
    time.sleep(0.2)

def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos &lt; 0 or pos &gt; 255:
        return (0, 0, 0)
    if pos &lt; 85:
        return (255 - pos * 3, pos * 3, 0)
    if pos &lt; 170:
        pos -= 85
        return (0, 255 - pos * 3, pos * 3)
    pos -= 170
    return (pos * 3, 0, 255 - pos * 3)


def rainbow_cycle(wait):
    for j in range(255):
        for i in range(NUM_LEDS):
            rc_index = (i * 256 // NUM_LEDS) + j
            pixels_set(i, wheel(rc_index
&amp; 255))
        pixels_show()
        time.sleep(wait)

BLACK = (0, 0, 0)
RED = (255, 0, 0)
YELLOW = (255, 150, 0)
GREEN = (0, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
PURPLE = (180, 0, 255)
WHITE = (255, 255, 255)
COLORS = (BLACK, RED, YELLOW, GREEN, CYAN, BLUE, PURPLE, WHITE)while True:

    print("fills")
    for color in COLORS:
        pixels_fill(color)
        pixels_show()
        time.sleep(0.2)

    print("chases")
    for color in COLORS:
        color_chase(color, 0.01)

    print("rainbow")
    rainbow_cycle(0)</code></pre>
</div>
</div>
<p>Thonny should now look like this:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-15.35.10.png" alt="The LED programming"></figure></div>
<p>One of the advantages of MicroPython is that much of it is readable English. For example, at the beginning of this program, we can see that Pico will control 31 LEDs via pin 28 and that they are to be set at maximum brightness (1 on a 0-1 scale where 0.5 is 50% brightness). The rest of the program instructs your Pico to display patterns and colours on the LEDs repeatedly.</p>
<p>Select <strong>File &gt; Save as&#8230;&#8203;</strong>:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-15.36.56.png" alt="Saving the file with Thonny"></figure></div>
<p>A prompt will appear asking you to specify where you want to save the file:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-15.38.00.png" alt="Saving a file to a Pico"></figure></div>
<p>Click on <strong>Raspberry Pi Pico</strong> and enter the file name <code>main.py</code>:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-15.38.48.png" alt="Naming the file main.py so the Pico automatically runs it after boot"></figure></div>
<p>It&#8217;s important to name the file <code>main.py</code> because Pico runs any file with this name automatically after booting. Congratulations: you&#8217;ve programmed your Pico!</p>
</div>
</div>
<div class="sect1">
<h2 id="construct-the-hardware">Construct the hardware</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="3d-printed-parts">3D-printed parts</h3>
<p>Four 3D-printed pieces are required to house all the component parts: the back, main body, Pico stand, and front. We will glue them together to form the complete assembly. You can download the <a href="https://www.printables.com/model/278332-raspberry-pi-pico-iron-man-arc-reactor">3D print files for free at printables.com</a>. Print them using any FDM (Fused Deposition Modelling) 3D printer with a build area of 70mm<sup>2</sup> or larger. We recommend you use a material that is easy to print with, such as PLA or PETG filament.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-15.02.24.png" alt="Find the 3D printed parts at printables.com"></figure></div>
</div>
<div class="sect2">
<h3 id="cutting-and-preparing-the-acrylic-discs">Cutting and preparing the acrylic discs</h3>
<p>For this project, you will need two acrylic discs 3mm thick and 70mm in diameter, one of which will require a hole approximately 5mm in diameter for wiring. If you have access to a laser cutter, making these is straightforward. Otherwise, it might be time to dig out your old pencil case and find a pair of compasses.</p>
<p>Using a jigsaw, cut out a 70mm circle and neaten up the edges with sandpaper or a file. The final discs don&#8217;t need to be absolutely flawless, since the subsequent steps will cover any minor imperfections. One disc should be drilled with a 5mm hole in the centre to allow wiring to pass through later:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-16.43.36.png" alt="A clear acrylic disc with a hole cut in the center"></figure></div>
<p>Mark a 70mm circle on your flexible adhesive mirror tile and another on your one-way mirror self-adhesive film. To make them perfectly round, cut them out using scissors. Ensure that you remove all the protective layers from your acrylic discs and then peel the adhesive backing from your mirror sheets in turn. Attach the circle of mirror tile sheet to the disc with the hole, which will be used to mount your Pico, and the circle of one-way mirror film to the other disc.</p>
</div>
<div class="sect2">
<h3 id="wire-and-solder-the-electronics">Wire and solder the electronics</h3>
<p>The Arc Reactor base contains the rechargeable battery, on/off switch, and USB-C charging board, all of which you need to glue into place inside the 3D-printed cutouts. At this stage, you need to do some cutting of wires, stripping and soldering. Use the photograph below as a reference to ensure that:</p>
<div class="ulist">
<ul>
<li>
<p>the positive and negative wires from the battery are soldered to the correct USB-C charging board positive and negative inputs</p>
</li>
<li>
<p>the positive output from the board is soldered to the centre pin of the sliding switch</p>
</li>
</ul>
</div>
<p>You can solder the positive wire from the switch to either of the two outer switch terminals:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-15.08.02.png" alt="USB-C charging board and battery mounted in the case"></figure></div>
<p>Next, solder three wires directly to the back of your Pico. The wires should be long enough to complete the wiring circuit later in the assembly process: about 20cm. To provide power to your Pico:</p>
<div class="ulist">
<ul>
<li>
<p>connect a red wires to the pin marked VBUS</p>
</li>
<li>
<p>connect a black wire to the pin marked GND</p>
</li>
</ul>
</div>
<p>Solder a third wire, shown here in blue, to the pin marked GP28. Our MicroPython script uses this pin to communicate with the LEDs:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-15.21.46.png" alt="Pico with wires threaded through the 3D printed stand"></figure><figcaption><em>Pico shown here with the wires threaded through the 3D printed stand</em></figcaption></div>
<p>LED strips usually come pre-wired, but their joints are often bulky, so we will make our own wiring loom. Using a pair of scissors, remove any pre-existing wiring and cut a strip of 31 LEDs. Be sure to cut along the line between LEDs:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-16.25.51.png" alt="Close-up of the line between LEDs"></figure></div>
<p>The strip is also marked with arrows to show the correct current direction, <strong>+</strong> symbols for the positive wire, <strong>0</strong> for the data wire, and <strong>G</strong> for the negative or ground wire. When cutting, be sure to snip down the middle of each solder pad. If you&#8217;re not careful, it could be tricky to solder the wires to the pads.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-18-at-16.35.13.png" alt="Wires soldered to the pads on an LED strip"></figure></div>
<p>Solder three more wires, also approximately 20cm in length, as shown in the photo above: red for positive, blue for data, and black for ground. You may find it more convenient to solder from the rear of the strip.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="assembly">Assembly</h2>
<div class="sectionbody">
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Feed the three wires attached to your Raspberry Pi Pico through the small 3D-printed Pico stand.</p>
</li>
<li>
<p>Thread the wires through the hole in the mirrored disc.</p>
</li>
<li>
<p>Glue the stand to the underside of your Pico and to the reflective side of the disc.</p>
</li>
<li>
<p>Ensure that Pico sits above the surface of the mirror on the stand to achieve the 3D infinity effect:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/IMG_0642-scaled.jpeg" alt="Pico sitting above the surface of the mirror to achieve an infinity effect"></figure></div>
</li>
<li>
<p>Place the disc with the one-way film in the main 3D-printed body.</p>
</li>
<li>
<p>Glue the front ring to the body. The front ring will conceal any minor imperfections in the disc.</p>
</li>
<li>
<p>Stick the strip of 31 LEDs around the inside of the 3D-printed body, ensuring that the wiring and connections are aligned with the gap in the body, so that you can easily pass the wires around the side of the disc on which your Pico is mounted. Most LED strips have self-adhesive backing, which makes this straightforward. Refer to this diagram to see how everything will fit together:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/Screenshot-2022-09-12-at-12.11.53-2.png" alt="Royale with Pico cheese"></figure><figcaption><em>Royale with Pico cheese</em></figcaption></div>
</li>
<li>
<p>With Pico already glued to its mirrored disc, you can now pair it with the main body housing the LEDs and the one-way mirror, and with the base containing the battery, charging board, and switch. Make sure that you have the ends of all your wires threaded through to the Arc Reactor base.</p>
</li>
<li>
<p>Solder (trimming any excess wire length as necessary):</p>
<div class="ulist">
<ul>
<li>
<p>the two blue data wires together</p>
</li>
<li>
<p>all three red positive wires together</p>
</li>
<li>
<p>all three negative ground wires together</p>
</li>
</ul>
</div>
</li>
</ol>
</div>
<p>Don&#8217;t forget to insulate your joins with heat shrink tubing or tape!</p>
</div>
</div>
<div class="sect1">
<h2 id="final-checks">Final checks</h2>
<div class="sectionbody">
<p>Before you glue the pieces together and make it final, check that everything is working as expected and that your LEDs are lighting up by sliding the switch. Check that the charging board functions by attaching a USB-C charger or battery pack: a small LED should illuminate when it&#8217;s charging.</p>
<p>Finally, glue the parts together.</p>
<figure class="wp-block-video"><iframe src="//www.youtube.com/embed/pMAs1BjGXro?rel=0" frameborder="0" allowfullscreen></iframe></figure>
<p>Congratulations. You have finished assembling your Arc Reactor!</p>
</div>
</div>
<div class="sect1">
<h2 id="moving-forward">Moving forward</h2>
<div class="sectionbody">
<p>Upgrades! Everyone enjoys an upgrade, especially Iron Man. Why not use a <a href="https://www.raspberrypi.com/news/how-to-run-a-webserver-on-raspberry-pi-pico-w/">Raspberry Pi Pico W running a webserver</a> to control your LEDs wirelessly from a browser on your smartphone? Or you could add a touch of paint and stick some velcro to the back of the reactor so that you can wear it on your chest like Tony Stark.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Build your own Iron Man Arc Reactor using a Raspberry Pi Pico, a strip of LEDs, and some wizardry to produce a 3D infinity mirror effect.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/ARC-REACTOR-500x333.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/ARC-REACTOR-500x333.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to build a Raspberry Pi NAS</title><link href="https://www.raspberrypi.com/tutorials/nas-box-raspberry-pi-tutorial/" rel="alternate" type="text/html" title="How to build a Raspberry Pi NAS" /><published>2022-12-25T00:00:00+00:00</published><updated>2022-12-25T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/nas-box-raspberry-pi-tutorial/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/nas-box-raspberry-pi-tutorial/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Network-attached storage (NAS) allows you to save files from your computer and mobile devices to external hard drives via your home or office wireless network. Using Raspberry Pi, you can connect your existing storage devices — such as external portable hard drives and USB flash drives — to create secure backups of all your important files, accessible from anywhere in the world.</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>suitable Raspberry Pi power supply (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">the power supply documentation for details</a>)</p>
</li>
<li>
<p>microSD card (see <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">the SD card documentation for details</a>)</p>
</li>
<li>
<p>adapter to connect your microSD card with <em>your usual computer</em></p>
</li>
<li>
<p>Powered USB hub</p>
</li>
<li>
<p>Ethernet cable</p>
</li>
<li>
<p>External USB storage</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network. We&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up as NAS.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi">Choose the right Raspberry Pi</h3>
<p>The faster your Raspberry Pi, the faster your data will save to your external storage. For this tutorial, we&#8217;ll be using a <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">Raspberry Pi 4 8GB</a>.</p>
</div>
<div class="sect2">
<h3 id="choose-the-right-storage">Choose the right storage</h3>
<p>Unless you&#8217;re very frugal with file sizes, an SD card probably isn&#8217;t large enough for NAS.</p>
<p>So in this tutorial, we&#8217;ll use a portable USB solid state drive (SSD). You could also use a USB flash drive or a USB hard disk drive (HDD). We recommend clearing your drive of data, as you may need to format it.</p>
<p>To maintain a consistent power supply to your external hard drives, it is best to use a powered USB hub to connect your storage to your Raspberry Pi.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">follow the Getting Started documentation to set up your Raspberry Pi</a>. For your operating system, choose <strong>Raspberry Pi OS Lite (32-bit)</strong> to run headless (without a mouse and keyboard).</p>
<p>During the OS customisation stage, edit settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-nas</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so your Pi can automatically connect to Wi-Fi</p>
</li>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your Wi-Fi settings or on a sticker on your router</p>
</li>
<li>
<p>Check the box next to <strong>Enable SSH</strong> so we can connect to the Pi without a mouse and keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="set-up-your-raspberry-pi">Set up your Raspberry Pi</h2>
<div class="sectionbody">
<p>For the best performance, connect your Raspberry Pi to your network via an Ethernet cable. For most people, this means connecting the device directly to your router.</p>
<p>Power down your Raspberry Pi by disconnecting it from the power supply.
Then, attach your storage to the powered USB hub, and the hub to your Raspberry Pi.
Finally, power your Raspberry Pi by plugging it back into the power supply.</p>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard and mouse. It&#8217;s perfect if your Raspberry Pi is located in a hard-to-reach location like the back of your television.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the hostname you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi&#8217;s IP address instead.</p>
<p>For more information about finding your IP address and remote accessing your Raspberry Pi, see <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">the remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-via-ssh">Connect via SSH</h3>
<p>Open a terminal session on <em>your usual computer</em>. To access your Raspberry Pi via SSH, run the following command, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-nas.local</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-nas.local
The authenticity of host 'pi-nas.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/
[fingerprint])? yes
Warning: Permanently added 'pi-nas.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-nas.local's password:
Linux pi-nas 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Oct 24 09:41:00 2023
&lt;username&gt;@pi-nas:~ $</code></pre>
</div>
</div>
<p>When asked for your password, use the password you created in Raspberry Pi Imager.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-storage">Configure storage</h2>
<div class="sectionbody">
<p>Now that the Raspberry Pi is up and running, it&#8217;s time to transform it into network storage.</p>
<div class="sect2">
<h3 id="find-your-drive">Find your drive</h3>
<p>First, we need to find the identifiers for the drives we want to format. To see the storage devices currently connected to your system, run the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ lsblk</code></pre>
</div>
</div>
<p>You should see output similar to the following:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0   1.8T  0 disk
mmcblk0     179:0    0 238.8G  0 disk
├─mmcblk0p1 179:1    0   256M  0 part /boot
└─mmcblk0p2 179:2    0 238.5G  0 part /</code></pre>
</div>
</div>
<p>This command describes storage devices connected to your Raspberry Pi. The <code>mmcblk0</code> device is your microSD card. The first USB storage device you connect should show up as Storage Device A, or <code>sda</code> for short. If you connect additional USB storage devices, you&#8217;ll see them as Storage Device B (<code>sdb</code>), C (<code>sdc</code>), etc.</p>
</div>
<div class="sect2">
<h3 id="partition-drive">Partition drive</h3>
<p>Next, partition your drive so Raspberry Pi OS recognizes it as a single storage device:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo fdisk /dev/sda</code></pre>
</div>
</div>
<p>When prompted:</p>
<div class="ulist">
<ul>
<li>
<p>Enter <code>n</code> to create a new partition.</p>
</li>
<li>
<p>If a partition already exists, use <code>d</code> to delete it.</p>
</li>
<li>
<p>Enter <code>p</code> for primary partition.</p>
</li>
</ul>
</div>
<p>Use the default option for all other prompts.</p>
<div class="admonitionblock warning" role="note"><h5 class="label">warning</h5><div class="inner">Back up all data stored on the external drive before you partition! The partition process will erase the drive.</div></div>
</div>
<div class="sect2">
<h3 id="format-drive">Format drive</h3>
<p>Now that the drive has been partitioned, we need to format it so Raspberry Pi OS can read and write data. The following command formats your drive into the <code>ext4</code> file system:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo mkfs.ext4 /dev/sda1</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="mount-drive">Mount drive</h3>
<p>Next, <a href="https://en.wikipedia.org/wiki/Mount_(computing)">mount</a> the drive to make it available to the file system on your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo mount /dev/sda1</code></pre>
</div>
</div>
<p>And ensure that the drive is mounted after each boot:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano /etc/fstab</code></pre>
</div>
</div>
<p>Add the following line at the end of the file:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">/dev/sda1 /mnt/sda1/ ext4 defaults,noatime 0 1</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with <code>nano</code>.</p>
</div>
<div class="sect2">
<h3 id="create-a-shared-folder">Create a shared folder</h3>
<p>Run the following command to create a shared folder on your drive:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo mkdir /mnt/sda1/shared</code></pre>
</div>
</div>
<p>Run the following command to grant read, write, and execute permissions to the folder to all users on your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo chmod -R 777 /mnt/sda1/shared</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="share-drive-over-your-network">Share drive over your network</h2>
<div class="sectionbody">
<p>Run the following command to install <a href="https://www.samba.org/">Samba</a>, a tool that shares directories over a network between computers:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt install samba samba-common-bin</code></pre>
</div>
</div>
<p>Then tell Samba to share the directory over the network. We can give Samba instructions via the Samba configuration file, <code>smb.conf</code>. Open the configuration file in an editor:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano /etc/samba/smb.conf</code></pre>
</div>
</div>
<p>And add the following line at the end of the file:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">[shared]
path=/mnt/sda1/shared
writeable=Yes
create mask=0777
directory mask=0777
public=no</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with <code>nano</code>.</p>
<p>Restart Samba to load the configuration changes:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo systemctl restart smbd</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="grant-drive-access">Grant drive access</h2>
<div class="sectionbody">
<p>Finally, you&#8217;ll want to grant access to your Samba share so only authenticated users can access files over the network.</p>
<p>Run the following command to create a user to manage Samba sharing:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo adduser pi-nas-user</code></pre>
</div>
</div>
<p>And add a password to that user with the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo smbpasswd -a username</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="access-from-macos">Access from macOS</h2>
<div class="sectionbody">
<p>From your desktop, press <strong>Command+K</strong>. Type <code>smb://pi-nas.local</code> and press the <strong>Enter</strong> key.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/macos-nas-access-connect.png" alt="Navigating to NAS storage using macOS Finder"></figure></div>
<p>Enter the username <code>pi-nas-user</code> and the password you chose in the <strong>Grant drive access</strong> step:</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/macos-nas-access-credentials.png" alt="Entering credentials for NAS storage using macOS Finder"></figure></div>
<p>Your shared folder will now show in a Finder window.</p>
</div>
</div>
<div class="sect1">
<h2 id="access-from-windows">Access from Windows</h2>
<div class="sectionbody">
<p>Open Windows Explorer. In the path bar, enter <code>pi-nas.local</code> and press the <strong>Enter</strong> key.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/windows-nas-access.png" alt="Navigating to NAS storage using Windows Explorer"></figure></div>
<p>That should create a new entry under <strong>Network</strong> in the left navigation bar and show its contents. Double-click on the share and enter the username <code>pi-nas-user</code> and the password you chose in the <strong>Grant drive access</strong> step when prompted.</p>
</div>
</div>
<div class="sect1">
<h2 id="access-from-ios">Access from iOS</h2>
<div class="sectionbody">
<p>You can connect your iPhone to your NAS system using the iOS Files app.</p>
<p>Open the app, navigate to the <strong>Browse</strong> view, and select the <strong>three dots</strong> icon in the top right of the screen.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/ios-nas-access-connect.png" alt="Navigating to NAS storage using iOS Files"></figure></div>
<p>You should see a <strong>Connect to Server</strong> option. Enter <code>pi-nas.local</code>.</p>
<p>Under <strong>Connect as</strong>, select <strong>Registered User</strong>. Enter the username <code>pi-nas-user</code> and the password you chose in the <strong>Grant drive access</strong> step.</p>
<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" src="https://www.raspberrypi.com/tutorials/tutorials/images/ios-nas-access-credentials.png" alt="Entering credentials for NAS storage using iOS Files"></figure></div>
<p>Tap <strong>Next</strong> in the upper right to connect.</p>
</div>
</div>
<div class="sect1">
<h2 id="next-steps">Next Steps</h2>
<div class="sectionbody">
<p>Now that you&#8217;ve got shared storage on your network, put it to good use! Use it to collaborate with friends and family quickly and easily. Donate all of your USB flash drives to a worthy cause, since you don&#8217;t need them any more to share data. Cut down on cloud storage usage by migrating large files onto your NAS.</p>
<p>To make your network storage configuration even nicer, consider setting up <a href="https://en.wikipedia.org/wiki/RAID">RAID</a> (Redundant Array of Inexpensive Disks) to protect your data from corruption and disk failures.</p>
<p>You might get annoyed at the rat&#8217;s nest of cables, hubs, and drives around your Raspberry Pi NAS. Don&#8217;t worry: <a href="https://www.thingiverse.com/search?q=raspberry+pi+nas&amp;page=1&amp;type=things&amp;sort=relevant">Thingiverse has you covered</a> with a variety of 3D printed case designs that will help you clean up the physical appearance of your drives and hubs.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[A Raspberry Pi NAS (network-attached storage) lets you save files from all your devices to external hard drives via your wireless network. Create secure backups of your files that are accessible from anywhere.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/NAS-BOX-800x533.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/NAS-BOX-800x533.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to use a Raspberry Pi in kiosk mode</title><link href="https://www.raspberrypi.com/tutorials/how-to-use-a-raspberry-pi-in-kiosk-mode/" rel="alternate" type="text/html" title="How to use a Raspberry Pi in kiosk mode" /><published>2022-12-25T00:00:00+00:00</published><updated>2022-12-25T00:00:00+00:00</updated><id>https://www.raspberrypi.com/tutorials/how-to-use-a-raspberry-pi-in-kiosk-mode/</id><content type="html" xml:base="https://www.raspberrypi.com/tutorials/how-to-use-a-raspberry-pi-in-kiosk-mode/"><![CDATA[<div id="preamble">
<div class="sectionbody">
<p>Kiosks are designed to offer users specific information or experiences while preventing access to any other activities on the device. They are often found in airports, shops, hospitals, cafes, and museums — any location where people need easy access to information or services like timetables, waiting times, product information, directions, self check-in machines, and so on.
Kiosk mode on a Raspberry Pi allows you to boot straight into a full‑screen web page or an application without using the desktop environment. It&#8217;s the foundation for many different projects that display information for a dedicated interaction with a user.
To demonstrate kiosk mode, we are going to set up a Raspberry Pi to boot automatically to a full‑screen <a href="https://raspberrypi.com">raspberrypi.com</a> web page, then alternate this with the <a href="https://time.is/London">time.is/London</a> web page.</p>
</div>
</div>
<div class="sect1">
<h2 id="supplies">Supplies</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Raspberry Pi</p>
</li>
<li>
<p>Suitable Raspberry Pi power supply (see the <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#power-supply">power supply documentation</a> for details)</p>
</li>
<li>
<p>microSD card (see the <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#sd-cards">SD card documentation</a> for details)</p>
</li>
<li>
<p>Display cable to connect your Raspberry Pi to your monitor (see the <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#display">display documentation</a> for details)</p>
</li>
<li>
<p>Monitor</p>
</li>
</ul>
</div>
<p>For the initial SD card setup, you will need:</p>
<div class="ulist">
<ul>
<li>
<p>Another computer connected to your network; we&#8217;ll refer to this as <em>your usual computer</em> to distinguish it from the Raspberry Pi computer you are setting up as the web kiosk</p>
</li>
<li>
<p>An adapter to connect your microSD card to <em>your usual computer</em> (alternatively, newer models of Raspberry Pi allow you to install an operating system <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#install-over-the-network">directly from the internet</a>)</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="choose-the-right-raspberry-pi">Choose the right Raspberry Pi</h3>
<p>Kiosk mode relies on you running a graphical web browser, and this in turn requires a Raspberry Pi 3 or newer with at least 1 GB of RAM (as both Chromium and Firefox will refuse to run on anything older). This tutorial also assumes that you&#8217;re using a Raspberry Pi with built-in Wi-Fi®, but it should be easy to adapt these instructions for wired Ethernet.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configure-your-raspberry-pi">Configure your Raspberry Pi</h2>
<div class="sectionbody">
<p>To begin, follow the <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system">'Getting started' documentation</a> to set up your Raspberry Pi. For your operating system, choose <strong>Raspberry Pi OS (64-bit)</strong>.</p>
<p>In this tutorial, we&#8217;re going to run the Raspberry Pi without a mouse or keyboard, so during Raspberry Pi Imager&#8217;s OS customisation stage, edit the settings as follows:</p>
<div class="ulist">
<ul>
<li>
<p>Enter a <strong>hostname</strong> of your choice (we suggest <code>pi-kiosk</code> for this tutorial)</p>
</li>
<li>
<p>Enter a <strong>username</strong> and <strong>password</strong>; you&#8217;ll need these later to authenticate</p>
</li>
<li>
<p>Check the box next to <strong>Configure wireless LAN</strong> so that your Raspberry Pi can automatically connect to Wi-Fi</p>
<div class="ulist">
<ul>
<li>
<p>Enter your network <strong>SSID</strong> (name) and <strong>password</strong>; you can find these in your network settings or on a sticker on your router</p>
</li>
</ul>
</div>
</li>
<li>
<p>On the <strong>Services</strong> tab, check the box next to <strong>Enable SSH</strong> so that we can connect to the Raspberry Pi without a mouse or keyboard</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="remotely-connect-to-your-raspberry-pi">Remotely connect to your Raspberry Pi</h2>
<div class="sectionbody">
<p>SSH allows you to wirelessly connect to your Raspberry Pi, eliminating the need for a keyboard or mouse. It&#8217;s perfect if your Raspberry Pi is located in a hard-to-reach location, like the back of your television.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>To SSH into the Raspberry Pi, you&#8217;ll use the <strong>hostname</strong> you set in Imager. If you have issues connecting using this method, you may want to use the Raspberry Pi&#8217;s IP address instead.</p>
<p>For more information about finding your IP address and remotely accessing your Raspberry Pi, see the <a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address">remote access documentation</a>.</p></div></div>
<div class="sect2">
<h3 id="connect-via-ssh">Connect via SSH</h3>
<p>Open a terminal session on <em>your usual computer</em>. To access your Raspberry Pi via SSH, run the following command, replacing <code>&lt;username&gt;</code> with the username you chose in Imager:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-kiosk.local
The authenticity of host 'pi-kiosk.local (fd81:b8a1:261d:1:acd4:610c:b069:ac16)' can't be established.
ED25519 key fingerprint is SHA256:s6aWAEe8xrbPmJzhctei7/gEQitO9mj2ilXigelBm04.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'pi-kiosk.local' (ED25519) to the list of known hosts.

&lt;username&gt;@pi-kiosk.local's password:
Linux pi-kiosk 6.1.21-v8+ #1642 SMP PREEMPT Mon Apr  3 17:24:16 BST 2023 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Oct 24 09:41:00 2023
&lt;username&gt;@pi-kiosk:~ $</code></pre>
</div>
</div>
<p>When asked for your password, use the password you created in Raspberry Pi Imager.</p>
<p>As the kiosk will be left unattended and/or displayed in a public place, it&#8217;s always a good idea to make sure that your software is <a href="https://www.raspberrypi.com/documentation/computers/os.html#update-software">up to date</a>.</p>
<p>Run this command to refresh the list of available updates:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt update</code></pre>
</div>
</div>
<p>Then run this command to install those updates:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt -y full-upgrade</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="set-up-kiosk-mode">Set up kiosk mode</h2>
<div class="sectionbody">
<p>This tutorial requires one additional piece of software, <code>wtype</code>, which simulates keyboard activity. To install it, run the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo apt -y install wtype</code></pre>
</div>
</div>
<p>Next, we&#8217;ll tell your Raspberry Pi what to present in kiosk mode and how to present it. In this tutorial, we&#8217;ll display the Raspberry Pi home page and a page showing the time in London, switching between the two every few seconds.</p>
<p>To achieve this, we will edit <code>.config/labwc/autostart</code>, which is a configuration file used to automatically run programs when the Raspberry Pi OS desktop has loaded.</p>
<p>Edit the <code>.config/labwc/autostart</code> file in <code>nano</code>, a text editor, by running the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nano .config/labwc/autostart</code></pre>
</div>
</div>
<p>Add the following two lines:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">chromium https://raspberrypi.com https://time.is/London --kiosk --noerrdialogs --disable-infobars --no-first-run --enable-features=OverlayScrollbar --start-maximized &amp;
~/switchtab.sh</code></pre>
</div>
</div>
<p>The first line opens the Chromium web browser in kiosk mode, with two tabs open: <code>raspberrypi.com</code> and <code>time.is</code>. The extra options alter kiosk mode in the following ways:</p>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>--noerrdialogs</code></dt>
<dd>
<p>Suppresses error messages</p>
</dd>
<dt class="hdlist1"><code>--disable-infobars</code></dt>
<dd>
<p>Disables notification infobars</p>
</dd>
<dt class="hdlist1"><code>--no-first-run</code></dt>
<dd>
<p>Skips the first-run setup experience that typically appears when launching for the first time</p>
</dd>
<dt class="hdlist1"><code>--enable-features=OverlayScrollbar</code></dt>
<dd>
<p>Scrollbars appear only when necessary and overlay content instead of using a dedicated scroll gutter</p>
</dd>
<dt class="hdlist1"><code>--start-maximized</code></dt>
<dd>
<p>Starts the browser in maximised full-screen mode</p>
</dd>
</dl>
</div>
<p>The second line executes a bash script (which we&#8217;ll create soon!) that automatically switches between the two tabs every ten seconds.</p>
<p>The ampersand (<code>&amp;</code>) at the end of the first line is very important, as it ensures that <em>both</em> lines in the <code>autostart</code> file are run in parallel. If it were omitted, <code>chromium</code> would run, but the <code>switchtab.sh</code> script wouldn&#8217;t. (Technically, if the ampersand were missing, the <code>switchtab.sh</code> script would run <em>after</em> <code>chromium</code> has finished running — but since we&#8217;re running Chromium in kiosk mode, there&#8217;s no way to quit it!)</p>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the edited file with <code>nano</code>.
Next, we&#8217;ll write the bash script that switches between the two tabs. Usually, the keyboard shortcut <strong>Ctrl+Tab</strong> cycles through open browser tabs. The script will use the program we installed, <code>wtype</code>, to simulate and automate these keystrokes. To create the script with <code>nano</code>, type:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nano ~/switchtab.sh</code></pre>
</div>
</div>
<p>Add the following to the file:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">#!/bin/bash

# Find Chromium browser process ID
chromium_pid=$(pgrep chromium | head -1)

# Check if Chromium is running
while [[ -z $chromium_pid ]]; do
  echo "Chromium browser is not running yet."
  sleep 5
  chromium_pid=$(pgrep chromium | head -1)
done

echo "Chromium browser process ID: $chromium_pid"

# Loop to send keyboard events
while true; do
  # Send Ctrl+Tab using `wtype` command
  wtype -M ctrl -P Tab -p Tab
  sleep 10
done</code></pre>
</div>
</div>
<p>This script first checks that the Chromium browser is running. If not, it waits five seconds before trying again (this gives Chromium enough time to launch before moving on). To toggle between the two tabs, the script uses <code>wtype</code> to simulate <strong>Ctrl+Tab</strong> every ten seconds.</p>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the new file with <code>nano</code>. Mark the file as executable so that it can be run as a script:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ chmod +x ~/switchtab.sh</code></pre>
</div>
</div>
<p>Finally, reboot your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Once your Raspberry Pi has rebooted, your display should be showing Chromium in kiosk mode, toggling between <code>raspberrypi.com</code> and <code>time.is</code> every ten seconds.</p>
<p>Depending on which websites your Raspberry Pi kiosk is displaying, you may want to temporarily plug a USB mouse into your Raspberry Pi so that you can dismiss any cookie pop-ups; the mouse can be unplugged again afterwards.</p>
</div>
</div>
<div class="sect1">
<h2 id="add-security-and-fail-safe-functionality">Add security and fail-safe functionality</h2>
<div class="sectionbody">
<p>Kiosk-mode devices run unattended for long periods of time and frequently restart. They are usually left unattended in public places, making them vulnerable to unwanted attention or interference. Kiosks can also be a potential target for hackers. None of this is conducive to a reliable, long-term kiosk-mode installation. Although it&#8217;s not realistic to make them 100% secure, there are a number of things we can do to protect devices running in kiosk mode.</p>
<div class="sect2">
<h3 id="hide-usb-ports">Hide USB ports</h3>
<p>As this project currently stands, simply plugging a keyboard and mouse into the USB ports on your Raspberry Pi would give an attacker full control. To defend against this, the Raspberry Pi should be placed in a physically secure case to make the ports inaccessible.</p>
</div>
<div class="sect2">
<h3 id="set-up-ssh-using-keys-rather-than-a-password">Set up SSH using keys rather than a password</h3>
<p>Until now, you have connected to your Raspberry Pi with SSH using a password. We can provide an extra layer of security by using pre-generated private-public ED25519 keys and removing the ability to log in with a username and password altogether. With key-based authentication, you&#8217;ll keep a private key on <em>your usual computer</em> and a public key on your Raspberry Pi. This variant of authentication is much harder to crack than a username and password. To create ED25519 keys (which are more secure than the older RSA keys), open a terminal on <em>your usual computer</em> and run the following:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh-keygen -t ed25519</code></pre>
</div>
</div>
<p>Accepting the defaults when prompted will create a private key and a public key. The location of these saved files is also given:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh-keygen
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/&lt;username&gt;/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/&lt;username&gt;/.ssh/id_ed25519
Your public key has been saved in /Users/&lt;username&gt;/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:u3Ry3y8g3tEo4TChzzjmebihkWqonbhVj7qiq3BsjMk &lt;username&gt;@&lt;hostname&gt;.local
The key's randomart image is:
+--[ED25519 256]--+
|                 |
|        .        |
|       . .       |
|      . o .      |
|    .  +S+ . o   |
|.= . ++ o.+ + .  |
|+E* +oo++.o+ o   |
|+*.+ o+o.=.....  |
|@=*.. .o.   . .o.|
+----[SHA256]-----+
$</code></pre>
</div>
</div>
<p>The <code>id_ed25519</code> file is your private key; do not share it. The <code>id_ed25519.pub</code> file is your public key. To use key-based authentication, transfer the public key to your Raspberry Pi.</p>
<p>Run the following command on <em>your usual computer</em> to print your public key to your terminal:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ cat ~/.ssh/id_ed25519.pub</code></pre>
</div>
</div>
<p>Copy the output of the command into your clipboard. Now, let&#8217;s move the public key onto your Raspberry Pi.</p>
<p>Connect to your Raspberry Pi over SSH:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-kiosk.local</code></pre>
</div>
</div>
<p>Then, create a folder called <code>.ssh</code> in your home directory:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ mkdir ~/.ssh</code></pre>
</div>
</div>
<p>Next, open a text editor for a new file named <code>authorized_keys</code> in the <code>.ssh</code> folder:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ nano ~/.ssh/authorized_keys</code></pre>
</div>
</div>
<p>Paste the contents of <code>id_ed25519.pub</code> from <em>your usual computer</em> into this file. Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the file with <code>nano</code>. Finally, disconnect from your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ exit</code></pre>
</div>
</div>
<p>Now try reconnecting, from <em>your usual computer</em>, to your Raspberry Pi via SSH again:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ ssh &lt;username&gt;@pi-kiosk.local</code></pre>
</div>
</div>
<p>If everything works as expected, you will no longer be prompted to enter a password. We can now disable password access completely by editing the <code>/etc/ssh/sshd_config</code> file:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo nano /etc/ssh/sshd_config</code></pre>
</div>
</div>
<p>Find the line that reads <code>#PasswordAuthentication yes</code>. Uncomment it by removing the <code>#</code>, then change <code>yes</code> to <code>no</code>, so that it looks like this:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session"># To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no</code></pre>
</div>
</div>
<p>Press <strong>Ctrl+X</strong>, then <strong>Y</strong>, and finally <strong>Enter</strong> to save the file with <code>nano</code>. Reboot your Raspberry Pi:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo reboot</code></pre>
</div>
</div>
<p>Now your Raspberry Pi is hardened against attacks over SSH.</p>
</div>
<div class="sect2">
<h3 id="sd-card-read-only-mode">SD card read-only mode</h3>
<p>Unplugging your Raspberry Pi to shut it down can eventually result in system file corruption. Any operating system stored on an SD card may eventually fail if used for long periods of time. To reduce these risks, you can set your SD card to read-only. Open the <code>raspi-config</code> tool with the following command:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell-session" data-lang="shell-session">$ sudo raspi-config</code></pre>
</div>
</div>
<p>Navigate through the menu system as follows:</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Select <code>Performance Options</code></p>
</li>
<li>
<p>Select <code>Overlay File System</code></p>
</li>
<li>
<p>Confirm that you would like to enable the overlay file system</p>
</li>
<li>
<p>Confirm that you would like to write-protect the boot partition</p>
</li>
<li>
<p>Press <strong>Tab</strong> to navigate to the <code>Finish</code> button</p>
</li>
<li>
<p>Confirm reboot</p>
</li>
</ol>
</div>
<p>This whole process may take a few minutes to complete.</p>
<div class="admonitionblock note" role="note"><h5 class="label">note</h5><div class="inner"><p>If you need to enable read-write access again to carry out an update or adjust your scripts, SSH back into your Raspberry Pi and use the above <code>raspi-config</code> command to disable the overlay file system, then reboot when prompted.</p>
<p>You can now carry out any work required. When you&#8217;ve tested your modifications, you&#8217;ll need to run <code>raspi-config</code> one more time to revert your SD card to a read-only state.</p></div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="take-kiosk-mode-further">Take kiosk mode further</h2>
<div class="sectionbody">
<p>This guide covers the basics of setting up a simple web page viewer in kiosk mode. From here, you can explore more complex kiosk projects, such as a CCTV viewing station, a home automation system, or perhaps the ultimate kiosk-mode project: a <a href="https://www.raspberrypi.com/tutorials/how-to-build-a-super-slim-smart-mirror/">magic mirror</a>. Our tutorial is based on <a href="https://magicmirror.builders/">Magic Mirror<sup>2</sup></a>, the winner of <a href="https://magazine.raspberrypi.com/"><em>The MagPi</em></a> (now <em>Raspberry Pi Official Magazine</em>)'s <a href="https://magazine.raspberrypi.com/issues/50">50th-issue</a> celebration feature, as voted by the Raspberry Pi community.</p>
</div>
</div>]]></content><author><name></name></author><category term="tutorial" /><summary type="html"><![CDATA[Kiosk mode lets you boot to a web page or application without giving users access to anything else. It's the basis for all kinds of projects.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.raspberrypi.com/tutorials/tutorials/images/KIOSK-800x533.jpg" /><media:content medium="image" url="https://www.raspberrypi.com/tutorials/tutorials/images/KIOSK-800x533.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>