Making a Raspberry Pi inventory (HPR Show 2496)

Dave Morriss


Table of Contents

Introduction

I have a number of Raspberry Pis – possibly too many – and I sometimes lose track of which is which, what model, size, name, address each one is. I wanted to be able to keep an inventory of them all, and to this end I wrote myself a little script that can be run on any Pi which will report useful information about it.

Every Pi has a unique serial number. Actually it’s randomly generated so there may be a few collisions but it’s close to unique! It also contains a revision number which encodes various items of information about it such as release date, model, PCB revision and memory. My script decodes this revision number for you based on a published table.

I run a Wikimedia instance on a Pi and have used this script to record details of my Pis there as well as what they are being used for and any planned projects. I now feel more organised!

Script

The script is called what_pi and uses Bash. The master copy is available on my GitLab repository or can be downloaded from HPR (or archive.org if you are reading these notes there). It is a work in progress and contains various notes pointing out possible shortcomings.

The script is listed below, but I will be brief in my description of its features in this episode.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/bin/bash -
#===============================================================================
#
#         FILE: what_pi
#
#        USAGE: ./what_pi
#
#  DESCRIPTION: To be run on a RPi. Reports back what model it is. Uses info
#               from /proc/cpuinfo and a lookup table from
#               http://elinux.org/RPi_HardwareHistory
#
#      OPTIONS: ---
# REQUIREMENTS: ---
#         BUGS: ---
#        NOTES: ---
#       AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
#      VERSION: 0.0.2
#      CREATED: 2016-06-17 18:17:47
#     REVISION: 2017-04-10 14:45:32
#
#===============================================================================

set -o nounset                              # Treat unset variables as an error

SCRIPT=${0##*/}

#===  FUNCTION  ================================================================
#         NAME: network_info
#  DESCRIPTION: Reports some basic network information in a (hopefully)
#               generalised way.
#               TODO: Make it deal with multiple interfaces properly
#   PARAMETERS: None
#      RETURNS: Nothing
#===============================================================================
network_info () {
    local d dev mac

    echo "Network information:"
    printf "  %-11s: %s\n" "Hostname" "$(hostname -f)"
    printf "  %-11s: %s\n" "IP" "$(hostname -I)"
    for d in /sys/class/net/*/address; do
        dev="${d%/*}"
        dev="${dev##*/}"
        if [[ $dev != 'lo' ]]; then
            mac="$(cat "$d")"
            printf "  %-11s: %s (%s)\n" "MAC" "$mac" "$dev"
        fi
    done
}

#===  FUNCTION  ================================================================
#         NAME: settings_info
#  DESCRIPTION: Reports stuff about settings and config file elements
#   PARAMETERS: None
#      RETURNS: Nothing
#===============================================================================
settings_info () {
    local codec

    #
    # Is the user in the 'video' group?
    #
    if id -Gn | grep -q 'video'; then
        echo "Various configuration and other settings:"
        echo "CPU $(vcgencmd measure_temp)"
        for codec in H264 MPG2 WVC1 MPG4 MJPG WMV9; do
            echo -e "$codec:\t$(vcgencmd codec_enabled $codec)"
        done
        vcgencmd get_config sdtv_mode
        vcgencmd get_config sdtv_aspect
    else
        echo "Can't run 'vgencmd'; you're not in the 'video' group"
    fi
}

#===  FUNCTION  ================================================================
#         NAME: cleanup_temp
#  DESCRIPTION: Cleanup temporary files in case of a keyboard interrupt
#               (SIGINT) or a termination signal (SIGTERM) and at script
#               exit
#   PARAMETERS: * - names of temporary files to delete
#      RETURNS: Nothing
#===============================================================================
function cleanup_temp {
    for tmp in "$@"; do
        [ -e "$tmp" ] && rm --force "$tmp"
    done
    exit 0
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#
# Are we on a Pi at all?
# TODO: Check this. It works on all my machines, but may not work everywhere
#
model=$(grep -m 1 '^model name' /proc/cpuinfo | cut -f2 -d:)
re="ARMv[0-9]"
if [[ ! $model =~ $re ]]; then
    echo "This doesn't seem to be a Raspberry Pi"
    exit 1
fi

#
# Make temporary files and set traps to delete them
#
TMP1=$(mktemp) || { echo "$SCRIPT: creation of temporary file failed!"; exit 1; }
TMP2=$(mktemp) || { echo "$SCRIPT: creation of temporary file failed!"; exit 1; }
trap 'cleanup_temp $TMP1 $TMP2' SIGHUP SIGINT SIGPIPE SIGTERM EXIT

#
# Create a table of Pi stuff. Copied from http://elinux.org/RPi_HardwareHistory
# using simple cut and paste. The result is a table separated by tabs, and
# this script relies on this fact.
# You will have to refresh this every time a new Pi model is released. This
# version is dated Q1 2017 and includes the Pi Zero W
#
cat > "$TMP1" <<'ENDTABLE'
Revision    Release Date    Model   PCB Revision    Memory  Notes
Beta    Q1 2012     B (Beta)     ?  256 MB  Beta Board
0002    Q1 2012     B   1.0     256 MB
0003    Q3 2012     B (ECN0001)     1.0     256 MB  Fuses mod and D14 removed
0004    Q3 2012     B   2.0     256 MB  (Mfg by Sony)
0005    Q4 2012     B   2.0     256 MB  (Mfg by Qisda)
0006    Q4 2012     B   2.0     256 MB  (Mfg by Egoman)
0007    Q1 2013     A   2.0     256 MB  (Mfg by Egoman)
0008    Q1 2013     A   2.0     256 MB  (Mfg by Sony)
0009    Q1 2013     A   2.0     256 MB  (Mfg by Qisda)
000d    Q4 2012     B   2.0     512 MB  (Mfg by Egoman)
000e    Q4 2012     B   2.0     512 MB  (Mfg by Sony)
000f    Q4 2012     B   2.0     512 MB  (Mfg by Qisda)
0010    Q3 2014     B+  1.0     512 MB  (Mfg by Sony)
0011    Q2 2014     Compute Module 1    1.0     512 MB  (Mfg by Sony)
0012    Q4 2014     A+  1.1     256 MB  (Mfg by Sony)
0013    Q1 2015     B+  1.2     512 MB   ?
0014    Q2 2014     Compute Module 1    1.0     512 MB  (Mfg by Embest)
0015     ?  A+  1.1     256 MB / 512 MB     (Mfg by Embest)
a01040  Unknown     2 Model B   1.0     1 GB    (Mfg by Sony)
a01041  Q1 2015     2 Model B   1.1     1 GB    (Mfg by Sony)
a21041  Q1 2015     2 Model B   1.1     1 GB    (Mfg by Embest)
a22042  Q3 2016     2 Model B (with BCM2837)    1.2     1 GB    (Mfg by Embest)
900021  Q3 2016     A+  1.1     512 MB  (Mfg by Sony)
900092  Q4 2015     Zero    1.2     512 MB  (Mfg by Sony)
900093  Q2 2016     Zero    1.3     512 MB  (Mfg by Sony)
920093  Q4 2016?    Zero    1.3     512 MB  (Mfg by Embest)
9000C1  Q1 2017     Zero W  1.1     512 MB  (Mfg by Sony)
a02082  Q1 2016     3 Model B   1.2     1 GB    (Mfg by Sony)
a020a0  Q1 2017     Compute Module 3 (and CM3 Lite)     1.0     1 GB    (Mfg by Sony)
a22082  Q1 2016     3 Model B   1.2     1 GB    (Mfg by Embest)
a32082  Q4 2016     3 Model B   1.2     1 GB    (Mfg by Sony Japan)
ENDTABLE

#
# Grab two values from the /proc/cpuinfo file
#
REV="$(grep '^Revision' /proc/cpuinfo | awk '{print $3}' | sed 's/^1000//')"
SER="$(grep '^Serial' /proc/cpuinfo | awk '{print $3}')"

#
# Make an Awk script which finds the details in the above table and displays
# them
#
cat > "$TMP2" <<'ENDPROG'
tolower($0) ~ rev {
    printf "%-13s: %s\n%-13s: %s\n%-13s: %s\n%-13s: %s\n%-13s: %s\n%-13s: %s\n%-13s: %s\n",
        "Revision",$1,
        "Release date",$2,
        "Model",$3,
        "PCB Revision",$4,
        "Memory",$5,
        "Notes",$6,
        "Serial no",serial
}
ENDPROG

#
# Run Awk on the table with the above script, passing the revision number as
# a regular expression for searching, and the serial number as a simple
# string.
#
awk -v "rev=^$REV" -v "serial=$SER" -F" *\t *" -f "$TMP2" "$TMP1"

#
# Report various settings and parameters
#
echo
settings_info

#
# Report network information
#
echo
network_info

exit

# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21

The process of identifying important features like the revision, release date and model of the Pi is achieved by searching a table of data. The table originates from the website http://elinux.org/RPi_HardwareHistory and has just been copied and pasted into this script. Whenever new Pis are released and the website is updated it will be necessary to refresh this table.

If you do this make sure that the tab characters used in this table are preserved since they are used as the field delimiter.

The searching of the table and display of results is performed using Awk, with a program that is stored in a temporary file and run on lines 163-181.

The script tries to check that it is running on a Pi in the code on lines 97-102. This works for me, but may not be universal.

Lines 107-109 contain commands that create temporary files and set up a mechanism to delete them using the trap command. The function cleanup_temp is used to delete the files, and that is defined on lines 76-89. I plan to talk about trap a forthcoming episode on the way Bash works.

Any improvements to this script are welcome. Please submit a pull request to the GitLab repository.

Example output

This file (example_output.txt) can be downloaded if desired. See the Links section below.

$ what_pi
Revision     : 0010
Release date : Q3 2014
Model        : B+
PCB Revision : 1.0
Memory       : 512 MB
Notes        : (Mfg by Sony)
Serial no    : 00000000deadbeef

Various configuration and other settings:
CPU temp=39.0'C
H264:   H264=enabled
MPG2:   MPG2=disabled
WVC1:   WVC1=disabled
MPG4:   MPG4=enabled
MJPG:   MJPG=enabled
WMV9:   WMV9=disabled
sdtv_mode=0
sdtv_aspect=0

Network information:
  Hostname   : rpi2
  IP         : 192.168.0.65 
  MAC        : b8:27:eb:22:de:ad (eth0)