Making Of#

Switch Sockets via wired network Challenge accepted

Analyze and Create#

Elicitate Requirements#

  • Customer is a friend - no money involved

  • Customer is a tech-savvy person in mechanical and electronic matters

  • User is a tech-savvy person as well, especially in software.

Identify Design Constraints#

  • No Wireless data transfer at all (no WiFi, no Bluetooth, …)

  • Connect the system to the environment via wired network

  • Straight-forward to the point of usage by a tech-savvy user

Create the System-Design#

../../_images/system_exploded_view.png

Exploded view of the system with its components and one of the neighbor systems.#

../../_images/system_assembled_view.png

Assembled view of the system with its components#

../../_images/system_assembled_view_detail_header_connections.png

Detailed view on interface between «component» RPI and «component» Relais. Red wire is connected to BCM pin 26, black wire is connected to GND (ground). See also Raspberry Pi Pinout#

../../_images/bd_system_boundaries_with_photo.svg

System Boundary Diagram with real components#

../../_images/bd_system_and_neighbors.svg

System Boundary Diagram with neighbors, their interfaces and logical and technical views#

I choose the command line tool pinctrl shipped with RPI-OS to be used to control the Relais via the GPIO pins of the RPI. No additional software is needed to be installed on the RPI or developed.

Realize#

Flash OS Image#

Get the Raspberry Pi OS Imager for Windows via scoop.sh. Use Powershell:

PS C:\> scoop install raspberry-pi-imager
--snip--
PS C:\>

Troubleshooting: In case scoop isn’t already installed then install it as follows and repeat the above command:

PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
PS C:\> Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
--snip--
PS C:\>

Use Raspberry Pi OS Imager to burn the image onto the SD-card:

../../_images/2024-09-01-10-53-46.png
../../_images/2024-08-30-18-03-50.png
../../_images/2024-09-01-14-05-34.png
../../_images/2024-09-01-14-05-04.png
../../_images/2024-09-01-14-06-12.png
../../_images/2024-08-30-18-05-39.png
../../_images/2024-08-30-18-04-54.png
../../_images/2024-09-01-14-08-13.png
../../_images/2024-09-01-14-08-47.png
../../_images/2024-08-30-18-06-08.png
../../_images/2024-09-01-14-14-05.png

Set GPIO settings after (re-)boot#

This is optional.

As default the GPIOs are OFF after reboot. Let’s change it as described in the RPI documentation:

Directly after flashing open on config.txt and append the following to the end of the file:

## GPIO settings
# Set pin 26 (BCM) to output and ON after (re-)boot
gpio=26=op,dh

# Set pin 19 (BCM) to output and ON after (re-)boot
gpio=19=op,dh

## EOF

Connect the System to the Environment#

../../_images/system_in_environment.png

Install Software#

Being logged on as user some_user on host some_host execute the following commands in a bash or git-bash:

1wget https://some_user.github.io/blog/2024-09-WeSwitch/_attachments/switch.py
2ssh-copy-id weswitch@weswitch
3scp switch.py weswitch@weswitch:~/
4ssh weswitch@weswitch "chmod +x switch.py"
5ssh weswitch@weswitch "sudo mv switch.py /usr/local/bin/switch"
6rm switch.py

Use System#

Being logged on as «user» some_user on «host» some_host execute the following commands in a bash or git-bash:

1some_electrical_device=26
2ssh weswitch@weswitch "switch $some_electrical_device"
3ssh weswitch@weswitch "switch $some_electrical_device:1"
4ssh weswitch@weswitch "switch $some_electrical_device:0"

Have a coffee with me#

Let’s enjoy our new tool and drink a ☕ together … 😁.

Discarded#

The procedure / walk#

We need an ssh client. If you’re under Linux, you have one. If you’re under Windows, you can use Putty or, what I recommend, just use the git-bash, its environment has ssh included.

If you don’t have git with git-bash, then just install it via scoop:

PS C:\> scoop install git
PS C:\>

Let’s enable password-less login via ssh:

 1some_user@some_host:~$ ssh-copy-id weswitch@weswitch
 2/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/c/Users/some_user/.ssh/id_rsa.pub"
 3/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
 4/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
 5weswitch@weswitch's password:
 6
 7Number of key(s) added: 1
 8
 9Now try logging into the machine, with:   "ssh 'weswitch@weswitch'"
10and check to make sure that only the key(s) you wanted were added.
11
12some_user@some_host:~$

Now let’s log onto system via ssh:

 1some_user@some_host:~$ ssh weswitch@weswitch
 2Linux weswitch 6.6.31+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.6.31-1+rpt1 (2024-05-29) aarch64
 3
 4The programs included with the Debian GNU/Linux system are free software;
 5the exact distribution terms for each program are described in the
 6individual files in /usr/share/doc/*/copyright.
 7
 8Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
 9permitted by applicable law.
10Last login: Sat Aug 31 08:31:12 2024
11weswitch@weswitch:~ $
Raspberry Pi GPIO - BCM Pinout#
+-----+------------+----RPI---+------------+-----+
| BCM |   Function | Physical | Function   | BCM |
+-----+------------+----++----+------------+-----+
|     |       3.3V |  1 || 2  | 5v         |     |
|  2  |   I2C1 SDA |  3 || 4  | 5v         |     |
|  3  |   I2C1 SCL |  5 || 6  | GND        |     |
|  4  |     GPCLK0 |  7 || 8  | UART TX    | 14  |
|     |        GND |  9 || 10 | UART RX    | 15  |
| 17  |            | 11 || 12 | PCM CLK    | 18  |
| 27  |            | 13 || 14 | GND        |     |
| 22  |            | 15 || 16 |            | 23  |
|     |       3.3V | 17 || 18 |            | 24  |
| 10  |  SPI0 MOSI | 19 || 20 | GND        |     |
|  9  |  SPI0 MISO | 21 || 22 |            | 25  |
| 11  |  SPI0 SCLK | 23 || 24 | SPI0 CE0   |  8  |
|     |        GND | 25 || 26 | SPI0 CE1   |  7  |
|  0  | EEPROM SDA | 27 || 28 | EEPROM SCL |  1  |
|  5  |            | 29 || 30 | GND        |     |
|  6  |            | 31 || 32 |            | 12  |
| 13  |       PWM1 | 33 || 34 | GND        |     |
| 19  |     PCM FS | 35 || 36 |            | 16  |
| 26  |            | 37 || 38 | PCM DIN    | 20  |
|     |        GND | 39 || 40 | PCM DOUT   | 21  |
+-----+------------+----++----+------------+-----+
../../_images/rpi_4b_pinout.png

Pin-out and orientation of 40-pin header of RPI 4B. Source/credits to: https://toptechboy.com/understanding-raspberry-pi-4-gpio-pinouts/#

 1weswitch@weswitch:~ $ python --version
 2Python 3.11.2
 3weswitch@weswitch:~ $ python -m pip install gpiozero
 4error: externally-managed-environment
 5
 6× This environment is externally managed
 7╰─> To install Python packages system-wide, try apt install
 8    python3-xyz, where xyz is the package you are trying to
 9    install.
10
11    If you wish to install a non-Debian-packaged Python package,
12    create a virtual environment using python3 -m venv path/to/venv.
13    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
14    sure you have python3-full installed.
15
16    For more information visit http://rptl.io/venv
17
18note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
19hint: See PEP 668 for the detailed specification.
20weswitch@weswitch:~ $ sudo apt-get install python3-gpiozero
21Reading package lists... Done
22Building dependency tree... Done
23Reading state information... Done
24python3-gpiozero is already the newest version (2.0-1).
250 upgraded, 0 newly installed, 0 to remove and 92 not upgraded.
26weswitch@weswitch:~ $

The AI-driven development loop:

 1weswitch@weswitch:~ $ touch switch.py && chmod +x switch.py
 2
 3weswitch@weswitch:~ $ # [A] Talk to the AI to get the code
 4weswitch@weswitch:~ $ # Copy the code into the clipboard and transfer it to the RPI
 5weswitch@weswitch:~ $ #
 6weswitch@weswitch:~ $ cat > switch.py
 7# Paste it from the clipboard with Mouse-Right-Click
 8# Hit Ctrl-D (EOF) to save the file
 9
10weswitch@weswitch:~ $ # Test the code
11weswitch@weswitch:~ $ ./switch.py
12weswitch@weswitch:~ $ # ...
13
14weswitch@weswitch:~ $ # Based on the results decide whether it needs rework or it's good to go ([A] or [B])
15weswitch@weswitch:~ $ # [B] Finish

Set up defined GPIO settings after (re-)boot.

As default the GPIOs are OFF after reboot. Let’s change it as described in the RPI documentation:

 1weswitch@weswitch:~ $ sudo vi /boot/firmware/config.txt
 2weswitch@weswitch:~ $ tail /boot/firmware/config.txt
 3
 4## GPIO settings
 5# Set pin 26 (BCM) to output and ON after (re-)boot
 6gpio=26=op,dh
 7
 8# Set pin 19 (BCM) to output and ON after (re-)boot
 9gpio=19=op,dh
10
11## EOF
12
13weswitch@weswitch:~ $

Find through thread of issue gpiozero#707 more infos about state-of-the-art command line tool for gpio control under RPI: pinctrl:

  1weswitch@weswitch:~ $ raspi-gpio --help
  2Unknown argument "--help" try "raspi-gpio help"
  3weswitch@weswitch:~ $ raspi-gpio help
  4
  5WARNING! raspi-gpio set writes directly to the GPIO control registers
  6ignoring whatever else may be using them (such as Linux drivers) -
  7it is designed as a debug tool, only use it if you know what you
  8are doing and at your own risk!
  9
 10The raspi-gpio tool is designed to help hack / debug BCM283x GPIO.
 11Running raspi-gpio with the help argument prints this help.
 12raspi-gpio can get and print the state of a GPIO (or all GPIOs)
 13and can be used to set the function, pulls and value of a GPIO.
 14raspi-gpio must be run as root.
 15Use:
 16raspi-gpio [<n>] get [GPIO]
 17OR
 18raspi-gpio [<n>] set <GPIO> [options]
 19OR
 20raspi-gpio [<n>] funcs [GPIO]
 21OR
 22raspi-gpio [<n>] raw
 23
 24<n> is an option GPIO chip index (default 0)
 25GPIO is a comma-separated list of pin numbers or ranges (without spaces),
 26e.g. 4 or 18-21 or 7,9-11
 27Note that omitting [GPIO] from raspi-gpio get prints all GPIOs.
 28raspi-gpio funcs will dump all the possible GPIO alt funcions in CSV format
 29or if [GPIO] is specified the alternate funcs just for that specific GPIO.
 30Valid [options] for raspi-gpio set are:
 31ip      set GPIO as input
 32op      set GPIO as output
 33a0-a5   set GPIO to alternate function alt0-alt5
 34pu      set GPIO in-pad pull up
 35pd      set GPIO in-pad pull down
 36pn      set GPIO pull none (no pull)
 37dh      set GPIO to drive to high (1) level (only valid if set to be an output)
 38dl      set GPIO to drive low (0) level (only valid if set to be an output)
 39Examples:
 40raspi-gpio get              Prints state of all GPIOs one per line
 41raspi-gpio get 20           Prints state of GPIO20
 42raspi-gpio get 20,21        Prints state of GPIO20 and GPIO21
 43raspi-gpio set 20 a5        Set GPIO20 to ALT5 function (GPCLK0)
 44raspi-gpio set 20 pu        Enable GPIO20 ~50k in-pad pull up
 45raspi-gpio set 20 pd        Enable GPIO20 ~50k in-pad pull down
 46raspi-gpio set 20 op        Set GPIO20 to be an output
 47raspi-gpio set 20 dl        Set GPIO20 to output low/zero (must already be set as an output)
 48raspi-gpio set 20 ip pd     Set GPIO20 to input with pull down
 49raspi-gpio set 35 a0 pu     Set GPIO35 to ALT0 function (SPI_CE1_N) with pull up
 50raspi-gpio set 20 op pn dh  Set GPIO20 to ouput with no pull and driving high
 51weswitch@weswitch:~ $ raspi-gpio gget 26
 52Unknown argument "gget" try "raspi-gpio help"
 53weswitch@weswitch:~ $ raspi-gpio get 26
 54GPIO 26: level=0 func=INPUT
 55[ raspi-gpio is deprecated - try `pinctrl` instead ]
 56weswitch@weswitch:~ $ pinctrl --help
 57Unknown option '--help' - try "pinctrl help"
 58weswitch@weswitch:~ $ pinctrl help
 59
 60WARNING! pinctrl set writes directly to the GPIO control registers
 61ignoring whatever else may be using them (such as Linux drivers) -
 62it is designed as a debug tool, only use it if you know what you
 63are doing and at your own risk!
 64
 65Running pinctrl with the help argument prints this help.
 66pinctrl can get and print the state of a GPIO (or all GPIOs)
 67and can be used to set the function, pulls and value of a GPIO.
 68pinctrl must be run as root.
 69Use:
 70pinctrl [-p] [-v] get [GPIO]
 71OR
 72pinctrl [-p] [-v] [-e] set <GPIO> [options]
 73OR
 74pinctrl [-p] [-v] poll [GPIO]
 75OR
 76pinctrl [-p] [-v] funcs [GPIO]
 77OR
 78pinctrl -c <chip> [funcs] [GPIO]
 79
 80GPIO is a comma-separated list of GPIO names, numbers or ranges (without
 81spaces), e.g. 4 or 18-21 or BT_ON,9-11
 82
 83Note that omitting [GPIO] from "pinctrl get" prints all GPIOs.
 84If the -p option is given, GPIO numbers are replaced by pin numbers on the
 8540-way header. If the -v option is given, the output is more verbose. Including
 86the -e option in a "set" causes pinctrl to echo back the new pin states.
 87pinctrl funcs will dump all the possible GPIO alt functions in CSV format
 88or if [GPIO] is specified the alternate funcs just for that specific GPIO.
 89The -c option allows the alt functions (and only the alt function) for a named
 90chip to be displayed, even if that chip is not present in the current system.
 91
 92Valid [options] for pinctrl set are:
 93ip      set GPIO as input
 94op      set GPIO as output
 95a1-a7   set GPIO to fsel in the range 1-7
 96no      set GPIO to no function (NONE)
 97pu      set GPIO in-pad pull up
 98pd      set GPIO pin-pad pull down
 99pn      set GPIO pull none (no pull)
100dh      set GPIO to drive high (1) level (only valid if set to be an output)
101dl      set GPIO to drive low (0) level (only valid if set to be an output)
102Examples:
103pinctrl get              Prints state of all GPIOs one per line
104pinctrl get 10           Prints state of GPIO10
105pinctrl get 10,11        Prints state of GPIO10 and GPIO11
106pinctrl set 10 a2        Set GPIO10 to fsel 2 function (nand_wen_clk)
107pinctrl -e set 10 pu     Enable GPIO10 ~50k in-pad pull up, echoing the result
108pinctrl set 10 pd        Enable GPIO10 ~50k in-pad pull down
109pinctrl set 10 op        Set GPIO10 to be an output
110pinctrl set 10 dl        Set GPIO10 to output low/zero (must already be set as an output)
111pinctrl set 10 ip pd     Set GPIO10 to input with pull down
112pinctrl set 35 a1 pu     Set GPIO35 to fsel 1 (jtag_2_clk) with pull up
113pinctrl set 20 op pn dh  Set GPIO20 to output with no pull and driving high
114pinctrl -c bcm2835 9-11  Display the alt functions for GPIOs 9-11 on bcm2835
115weswitch@weswitch:~ $ pinctrl get 10
11610: ip    -- | lo // GPIO10 = input
117weswitch@weswitch:~ $ pinctrl get 26
11826: ip    -- | lo // GPIO26 = input
119weswitch@weswitch:~ $ pinctrl set 26 op
120weswitch@weswitch:~ $ pinctrl set 26 dh
121weswitch@weswitch:~ $ pinctrl set 26 dl
122weswitch@weswitch:~ $ pinctrl set 26 dh
123weswitch@weswitch:~ $ pinctrl set 26 dl
124weswitch@weswitch:~ $
weswitch@weswitch:~ $ sudo tee -a /boot/firmware/config.txt > /dev/null

## GPIO settings
# Set pin 26 (BCM) to output and ON after (re-)boot
gpio=26=op,dh

# Set pin 19 (BCM) to output and ON after (re-)boot
gpio=19=op,dh

## EOF
weswitch@weswitch:~ $ tail /boot/firmware/config.txt


## GPIO settings
# Set pin 26 (BCM) to output and ON after (re-)boot
gpio=26=op,dh

# Set pin 19 (BCM) to output and ON after (re-)boot
gpio=19=op,dh

## EOF
weswitch@weswitch:~ $ sudo reboot
 1weswitch@weswitch:~ $ sudo reboot
 2
 3Broadcast message from root@weswitch on pts/1 (Sun 2024-09-01 15:10:10 CEST):
 4
 5The system will reboot now!
 6
 7weswitch@weswitch:~ $ Connection to weswitch closed by remote host.
 8Connection to weswitch closed.
 9some_user@some_host:~$ ssh weswitch@weswitch "pinctrl set 26 dh"
10some_user@some_host:~$ ssh weswitch@weswitch "pinctrl set 26 dl"
11some_user@some_host:~$ ssh weswitch@weswitch "pinctrl set 26 dh"
12some_user@some_host:~$ ssh weswitch@weswitch "pinctrl help"
13
14WARNING! pinctrl set writes directly to the GPIO control registers
15ignoring whatever else may be using them (such as Linux drivers) -
16it is designed as a debug tool, only use it if you know what you
17are doing and at your own risk!
18
19Running pinctrl with the help argument prints this help.
20pinctrl can get and print the state of a GPIO (or all GPIOs)
21and can be used to set the function, pulls and value of a GPIO.
22pinctrl must be run as root.
23Use:
24pinctrl [-p] [-v] get [GPIO]
25OR
26pinctrl [-p] [-v] [-e] set <GPIO> [options]
27OR
28pinctrl [-p] [-v] poll [GPIO]
29OR
30pinctrl [-p] [-v] funcs [GPIO]
31OR
32pinctrl -c <chip> [funcs] [GPIO]
33
34GPIO is a comma-separated list of GPIO names, numbers or ranges (without
35spaces), e.g. 4 or 18-21 or BT_ON,9-11
36
37Note that omitting [GPIO] from "pinctrl get" prints all GPIOs.
38If the -p option is given, GPIO numbers are replaced by pin numbers on the
3940-way header. If the -v option is given, the output is more verbose. Including
40the -e option in a "set" causes pinctrl to echo back the new pin states.
41pinctrl funcs will dump all the possible GPIO alt functions in CSV format
42or if [GPIO] is specified the alternate funcs just for that specific GPIO.
43The -c option allows the alt functions (and only the alt function) for a named
44chip to be displayed, even if that chip is not present in the current system.
45
46Valid [options] for pinctrl set are:
47ip      set GPIO as input
48op      set GPIO as output
49a1-a7   set GPIO to fsel in the range 1-7
50no      set GPIO to no function (NONE)
51pu      set GPIO in-pad pull up
52pd      set GPIO pin-pad pull down
53pn      set GPIO pull none (no pull)
54dh      set GPIO to drive high (1) level (only valid if set to be an output)
55dl      set GPIO to drive low (0) level (only valid if set to be an output)
56Examples:
57pinctrl get              Prints state of all GPIOs one per line
58pinctrl get 10           Prints state of GPIO10
59pinctrl get 10,11        Prints state of GPIO10 and GPIO11
60pinctrl set 10 a2        Set GPIO10 to fsel 2 function (nand_wen_clk)
61pinctrl -e set 10 pu     Enable GPIO10 ~50k in-pad pull up, echoing the result
62pinctrl set 10 pd        Enable GPIO10 ~50k in-pad pull down
63pinctrl set 10 op        Set GPIO10 to be an output
64pinctrl set 10 dl        Set GPIO10 to output low/zero (must already be set as an output)
65pinctrl set 10 ip pd     Set GPIO10 to input with pull down
66pinctrl set 35 a1 pu     Set GPIO35 to fsel 1 (jtag_2_clk) with pull up
67pinctrl set 20 op pn dh  Set GPIO20 to output with no pull and driving high
68pinctrl -c bcm2835 9-11  Display the alt functions for GPIOs 9-11 on bcm2835
69some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 26 dl"
70some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 19 dl"
71some_user@some_host:~$ ssh weswitch@weswitch "sudo init 6"
72some_user@some_host:~$
  1some_user@some_host:~$ ssh-copy-id weswitch@weswitch
  2/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/c/Users/some_user/.ssh/id_rsa.pub"
  3The authenticity of host 'weswitch (192.168.1.110)' can't be established.
  4ED25519 key fingerprint is SHA256:TPMVfBCS/noxz4hr1w3rRYpVxk5YKuM418legTAkpjw.
  5This key is not known by any other names.
  6Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  7/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
  8/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
  9weswitch@weswitch's password:
 10
 11Number of key(s) added: 1
 12
 13Now try logging into the machine, with:   "ssh 'weswitch@weswitch'"
 14and check to make sure that only the key(s) you wanted were added.
 15
 16some_user@some_host:~$ ssh weswitch@weswitch "tail /boot/firmware/config.txt"
 17[cm4]
 18# Enable host mode on the 2711 built-in XHCI USB controller.
 19# This line should be removed if the legacy DWC2 controller is required
 20# (e.g. for USB device mode) or if USB support is not required.
 21otg_mode=1
 22
 23[cm5]
 24dtoverlay=dwc2,dr_mode=host
 25
 26[all]
 27some_user@some_host:~$ ssh weswitch@weswitch "sudo tee -a /boot/firmware/config.txt > /dev/null"
 28
 29## GPIO settings
 30# Set pin 26 (BCM) to output and ON after (re-)boot
 31gpio=26=op,dh
 32
 33# Set pin 19 (BCM) to output and ON after (re-)boot
 34gpio=19=op,dh
 35
 36## EOF
 37weswitch@weswitch:~ $ tail /boot/firmware/config.txt
 38
 39
 40## GPIO settings
 41# Set pin 26 (BCM) to output and ON after (re-)boot
 42gpio=26=op,dh
 43
 44# Set pin 19 (BCM) to output and ON after (re-)boot
 45gpio=19=op,dh
 46
 47## EOF
 48some_user@some_host:~$ ssh weswitch@weswitch "tail /boot/firmware/config.txt"
 49
 50
 51## GPIO settings
 52# Set pin 26 (BCM) to output and ON after (re-)boot
 53gpio=26=op,dh
 54
 55# Set pin 19 (BCM) to output and ON after (re-)boot
 56gpio=19=op,dh
 57
 58## EOF
 59some_user@some_host:~$ ssh weswitch@weswitch "sudo reboot"
 60some_user@some_host:~$
 61
 62
 63some_user@some_host:~$ ssh weswitch@weswitch "pinctrl help"
 64
 65WARNING! pinctrl set writes directly to the GPIO control registers
 66ignoring whatever else may be using them (such as Linux drivers) -
 67it is designed as a debug tool, only use it if you know what you
 68are doing and at your own risk!
 69
 70Running pinctrl with the help argument prints this help.
 71pinctrl can get and print the state of a GPIO (or all GPIOs)
 72and can be used to set the function, pulls and value of a GPIO.
 73pinctrl must be run as root.
 74Use:
 75pinctrl [-p] [-v] get [GPIO]
 76OR
 77pinctrl [-p] [-v] [-e] set <GPIO> [options]
 78OR
 79pinctrl [-p] [-v] poll [GPIO]
 80OR
 81pinctrl [-p] [-v] funcs [GPIO]
 82OR
 83pinctrl -c <chip> [funcs] [GPIO]
 84
 85GPIO is a comma-separated list of GPIO names, numbers or ranges (without
 86spaces), e.g. 4 or 18-21 or BT_ON,9-11
 87
 88Note that omitting [GPIO] from "pinctrl get" prints all GPIOs.
 89If the -p option is given, GPIO numbers are replaced by pin numbers on the
 9040-way header. If the -v option is given, the output is more verbose. Including
 91the -e option in a "set" causes pinctrl to echo back the new pin states.
 92pinctrl funcs will dump all the possible GPIO alt functions in CSV format
 93or if [GPIO] is specified the alternate funcs just for that specific GPIO.
 94The -c option allows the alt functions (and only the alt function) for a named
 95chip to be displayed, even if that chip is not present in the current system.
 96
 97Valid [options] for pinctrl set are:
 98ip      set GPIO as input
 99op      set GPIO as output
100a1-a7   set GPIO to fsel in the range 1-7
101no      set GPIO to no function (NONE)
102pu      set GPIO in-pad pull up
103pd      set GPIO pin-pad pull down
104pn      set GPIO pull none (no pull)
105dh      set GPIO to drive high (1) level (only valid if set to be an output)
106dl      set GPIO to drive low (0) level (only valid if set to be an output)
107Examples:
108pinctrl get              Prints state of all GPIOs one per line
109pinctrl get 10           Prints state of GPIO10
110pinctrl get 10,11        Prints state of GPIO10 and GPIO11
111pinctrl set 10 a2        Set GPIO10 to fsel 2 function (nand_wen_clk)
112pinctrl -e set 10 pu     Enable GPIO10 ~50k in-pad pull up, echoing the result
113pinctrl set 10 pd        Enable GPIO10 ~50k in-pad pull down
114pinctrl set 10 op        Set GPIO10 to be an output
115pinctrl set 10 dl        Set GPIO10 to output low/zero (must already be set as an output)
116pinctrl set 10 ip pd     Set GPIO10 to input with pull down
117pinctrl set 35 a1 pu     Set GPIO35 to fsel 1 (jtag_2_clk) with pull up
118pinctrl set 20 op pn dh  Set GPIO20 to output with no pull and driving high
119pinctrl -c bcm2835 9-11  Display the alt functions for GPIOs 9-11 on bcm2835
120some_user@some_host:~$
121
122some_user@some_host:~$ ssh weswitch@weswitch "pinctrl get 26"
12326: op -- pd | hi // GPIO26 = output
124some_user@some_host:~$ ssh weswitch@weswitch "pinctrl get 19"
12519: op -- pd | hi // GPIO19 = output
126some_user@some_host:~$ ssh weswitch@weswitch "pinctrl set 26 dl"
127some_user@some_host:~$ ssh weswitch@weswitch "pinctrl get 26"
12826: op -- pd | lo // GPIO26 = output
129some_user@some_host:~$ ssh weswitch@weswitch "pinctrl set 19 dl"
130some_user@some_host:~$ ssh weswitch@weswitch "pinctrl get 19"
13119: op -- pd | lo // GPIO19 = output
132some_user@some_host:~$ ssh weswitch@weswitch "pinctrl set 26 dh ; pinctrl 19 dh"
133some_user@some_host:~$
134
135some_user@some_host:~$ ssh weswitch@weswitch "sudo shutdown now"
136System is going down. Unprivileged users are not permitted to log in anymore. For technical details, see pam_nologin(8).
137
138Connection closed by 192.168.1.110 port 22
139some_user@some_host:~$
 1some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 19 ; pinctrl 26"
 219: op -- pd | hi // GPIO19 = output
 326: op -- pd | hi // GPIO26 = output
 4some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 19 dl ; pinctrl 26 dl"
 5some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 19 ; pinctrl 26"
 619: op -- pd | lo // GPIO19 = output
 726: op -- pd | lo // GPIO26 = output
 8some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 19 dh ; pinctrl 26 dh"
 9some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 19 ; pinctrl 26"
1019: op -- pd | hi // GPIO19 = output
1126: op -- pd | hi // GPIO26 = output
12some_user@some_host:~$
1some_user@some_host:~$ ssh-copy-id weswitch@weswitch
2--snip--
3some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 26"
426: op -- pd | hi // GPIO26 = output
5some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 26 dl"
6some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 26"
726: op -- pd | lo // GPIO26 = output
8some_user@some_host:~$ ssh weswitch@weswitch "pinctrl 26 dh"

Results#

As downloads#

Inlined here#

Resulting switch.py#
  1#!/usr/bin/env python3
  2
  3# MIT License
  4#
  5# Copyright (c) 2024 Alexander Mann-Wahrenberg (basejumpa)
  6#
  7# Permission is hereby granted, free of charge, to any person obtaining a copy
  8# of this software and associated documentation files (the "Software"), to deal
  9# in the Software without restriction, including without limitation the rights
 10# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11# copies of the Software, and to permit persons to whom the Software is
 12# furnished to do so, subject to the following conditions:
 13#
 14# The above copyright notice and this permission notice shall be included in all
 15# copies or substantial portions of the Software.
 16#
 17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 23# SOFTWARE.
 24
 25import argparse
 26import sys
 27import re
 28from gpiozero import LED
 29import gpiozero.pins.rpigpio
 30
 31
 32def close(self):
 33    pass
 34
 35def parse_state(state):
 36    true_values = {"true", "1", "on", "t", "yes"}
 37    false_values = {"false", "0", "off", "f", "no"}
 38
 39    state_lower = state.lower()
 40    if state_lower in true_values:
 41        return "True"
 42    elif state_lower in false_values:
 43        return "False"
 44    else:
 45        raise argparse.ArgumentTypeError(f"Invalid state value: '{state}'")
 46
 47def parse_pin_state(pin_state):
 48    match = re.match(r"^(\d+)(:(1|0))?$", pin_state)
 49    if match:
 50        pin = int(match.group(1))
 51        state = "True" if match.group(3) == "1" else "False" if match.group(3) == "0" else None
 52        return pin, state
 53    else:
 54        raise argparse.ArgumentTypeError(f"Invalid pin:state format: '{pin_state}'")
 55
 56def main():
 57
 58    pinout = """
 59    Raspberry Pi GPIO - BCM Pinout
 60    +-----+------------+----RPI---+------------+-----+
 61    | BCM |   Function | Physical | Function   | BCM |
 62    +-----+------------+----++----+------------+-----+
 63    |     |       3.3V |  1 || 2  | 5v         |     |
 64    |  2  |   I2C1 SDA |  3 || 4  | 5v         |     |
 65    |  3  |   I2C1 SCL |  5 || 6  | GND        |     |
 66    |  4  |     GPCLK0 |  7 || 8  | UART TX    | 14  |
 67    |     |        GND |  9 || 10 | UART RX    | 15  |
 68    | 17  |            | 11 || 12 | PCM CLK    | 18  |
 69    | 27  |            | 13 || 14 | GND        |     |
 70    | 22  |            | 15 || 16 |            | 23  |
 71    |     |       3.3V | 17 || 18 |            | 24  |
 72    | 10  |  SPI0 MOSI | 19 || 20 | GND        |     |
 73    |  9  |  SPI0 MISO | 21 || 22 |            | 25  |
 74    | 11  |  SPI0 SCLK | 23 || 24 | SPI0 CE0   |  8  |
 75    |     |        GND | 25 || 26 | SPI0 CE1   |  7  |
 76    |  0  | EEPROM SDA | 27 || 28 | EEPROM SCL |  1  |
 77    |  5  |            | 29 || 30 | GND        |     |
 78    |  6  |            | 31 || 32 |            | 12  |
 79    | 13  |       PWM1 | 33 || 34 | GND        |     |
 80    | 19  |     PCM FS | 35 || 36 |            | 16  |
 81    | 26  |            | 37 || 38 | PCM DIN    | 20  |
 82    |     |        GND | 39 || 40 | PCM DOUT   | 21  |
 83    +-----+------------+----++----+------------+-----+
 84    """
 85
 86    examples = """
 87    Examples:
 88
 89    1. Query the state of a pin:
 90        ./switch.py --pin 19
 91        ./switch.py 26
 92        Output: "19:0" on stdout, "Pin 19 is currently OFF" on stderr
 93
 94    2. Turn on a pin using the --pin option:
 95        ./switch.py True --pin 26
 96        ./switch.py 1 --pin 26
 97        ./switch.py on --pin 26
 98
 99    3. Turn off a pin using the --pin option:
100        ./switch.py False --pin 26
101        ./switch.py 0 --pin 26
102        ./switch.py off --pin 26
103
104    4. Turn on a pin using the pin:state format:
105        ./switch.py 26:1
106
107    5. Turn off a pin using the pin:state format:
108        ./switch.py 19:0
109    """
110
111    parser = argparse.ArgumentParser(
112        description=(
113            "Control a GPIO pin (use BCM numbering).\n\n"
114            + examples
115            + pinout
116            + "More detailed/interactive at: https://pinout.xyz/\n"
117        ),
118        formatter_class=argparse.RawTextHelpFormatter
119    )
120
121    parser.add_argument(
122        "command",
123        nargs="?",
124        help="Set the pin state in the format <pin>:<state> (e.g., 26:1 or 19:0) or use positional True/False with --pin. Providing only the pin number queries the pin state.",
125    )
126
127    parser.add_argument(
128        "--pin",
129        type=int,
130        help="BCM pin number to control (required if using positional True/False).",
131    )
132
133    args = parser.parse_args()
134
135    if not args.command and not args.pin:
136        parser.print_help()
137        sys.exit(1)
138
139    if args.command:
140        pin, state = parse_pin_state(args.command)
141        if state is None and args.pin is None:
142            # If only a pin is provided, query the pin state
143            state = None
144        elif state is None and args.pin is not None:
145            # Handle the True/False positional argument with --pin
146            state = parse_state(args.command)
147            pin = args.pin
148    else:
149        # If no command is provided, just query the pin state
150        pin = args.pin
151        state = None
152
153    # Override the close method to prevent the GPIO pin from being closed when application exits
154    gpiozero.pins.rpigpio.RPiGPIOPin.close = close
155
156    # Use the pin and state
157    pin_control = LED(pin, pin_factory=gpiozero.pins.rpigpio.RPiGPIOFactory())
158
159    # Determine the current state
160    current_state = "True" if pin_control.is_lit else "False"
161
162    if state is None:
163        # If no state is provided, just output the current state
164        machine_readable_state = "1" if current_state == "True" else "0"
165        human_readable_state = "ON" if current_state == "True" else "OFF"
166        print(f"{pin}:{machine_readable_state}", file=sys.stdout)  # Machine-readable
167        print(f"Pin {pin} is currently {human_readable_state}", file=sys.stderr)  # Human-readable
168    else:
169        # Determine if the state is changing
170        if state == current_state:
171            print(f"{pin}:{('1' if state == 'True' else '0')}", file=sys.stdout)  # Machine-readable
172            print(f"Pin {pin} is already {('ON' if state == 'True' else 'OFF')}. No change made.", file=sys.stderr)  # Human-readable
173        else:
174            # Set the pin state based on the provided argument
175            if state == "True":
176                pin_control.on()
177                print(f"{pin}:1", file=sys.stdout)  # Machine-readable
178                print(f"Pin {pin} is now ON. State changed from OFF to ON.", file=sys.stderr)  # Human-readable
179            else:
180                pin_control.off()
181                print(f"{pin}:0", file=sys.stdout)  # Machine-readable
182                print(f"Pin {pin} is now OFF. State changed from ON to OFF.", file=sys.stderr)  # Human-readable
183
184if __name__ == "__main__":
185    main()
186
Resulting README.md#
# `switch` - GPIO Pin Control Tool

## Overview

`switch` is a tool implemented in Python designed to control a GPIO pin on a Raspberry Pi. The script allows you to turn a GPIO pin on or off (using True/False or similar commands), query its current state, and set the pin number.

This script is particularly useful for controlling LEDs or other simple devices connected to the GPIO pins.

## Installation

1. Ensure Python 3 and the `gpiozero` library are installed on your Raspberry Pi.

   ```bash
   sudo apt-get update
   sudo apt-get install python3 python3-gpiozero
   ```

2. Download or copy `switch.py` to your Raspberry Pi.

3. (Optional) Make the script executable:

   ```bash
   chmod +x switch.py
   ```

4. (Optional) Move the script to a directory in your `PATH` (e.g., `/usr/local/bin`) for easy access:

   ```bash
   sudo mv switch.py /usr/local/bin/switch
   ```

## Usage

### Basic Command Structure

```bash
switch [True|False] [--pin PIN]
switch <pin>:<state>
switch <pin>
```

- **True/False**: Set the pin to `True` (ON) or `False` (OFF).
- **<pin>:<state>**: Set the state of the specified pin directly, where `state` is `1` (ON) or `0` (OFF).
- **<pin>**: Query the state of the specified pin.
- **--pin PIN**: Specify the BCM pin number to control. Required when using the `True/False` format.

### Examples

1. **Query the state of a pin**:
   ```bash
   ./switch.py --pin 19
   ./switch.py 26
   ```
   - Output: `19:0` on stdout, `Pin 19 is currently OFF` on stderr.

2. **Turn on a pin using the --pin option**:
   ```bash
   ./switch.py True --pin 26
   ./switch.py 1 --pin 26
   ./switch.py on --pin 26
   ```

3. **Turn off a pin using the --pin option**:
   ```bash
   ./switch.py False --pin 26
   ./switch.py 0 --pin 26
   ./switch.py off --pin 26
   ```

4. **Turn on a pin using the pin:state format**:
   ```bash
   ./switch.py 26:1
   ```

5. **Turn off a pin using the pin:state format**:
   ```bash
   ./switch.py 19:0
   ```

### Input Tolerance

The script accepts various forms of input for `True` and `False`:

- **True**: `True`, `true`, `1`, `on`, `On`, `ON`, `t`, `yes`
- **False**: `False`, `false`, `0`, `off`, `Off`, `OFF`, `f`, `no`

### Help Screen

For more information, run:

```bash
switch.py --help
```

This will display:

```
usage: switch.py [-h] [--pin PIN] [True | False]

Control a GPIO pin.

Pinout information can be found at: https://pinout.xyz/

Examples:

    1. Query the state of a pin:
       ./switch.py --pin 19
       ./switch.py 26
       Output: "19:0" on stdout, "Pin 19 is currently OFF" on stderr

    2. Turn on a pin using the --pin option:
       ./switch.py True --pin 26
       ./switch.py 1 --pin 26
       ./switch.py on --pin 26

    3. Turn off a pin using the --pin option:
       ./switch.py False --pin 26
       ./switch.py 0 --pin 26
       ./switch.py off --pin 26

    4. Turn on a pin using the pin:state format:
       ./switch.py 26:1

    5. Turn off a pin using the pin:state format:
       ./switch.py 19:0

positional arguments:
  {True,False}        Set the pin to True (ON) or False (OFF).

optional arguments:
  -h, --help          show this help message and exit
  --pin PIN           BCM pin number to control.
```

### Pinout Information

For detailed pinout information on your Raspberry Pi, visit [pinout.xyz](https://pinout.xyz/).

## Troubleshooting

If you don't see the expected behavior on the electrical side (e.g., the LED doesn't turn on/off):

- **Verify the Pin Numbering**: Ensure you are using the correct BCM pin number.
- **Check the Wiring**: Make sure the LED and resistor are correctly connected.
- **Check the LED Polarity**: The longer leg (anode) should be connected to the GPIO pin, and the shorter leg (cathode) should be connected to ground.
- **Test the Pin**: Use a simple script to manually test turning the pin on and off.

## License

```
MIT License

Copyright (c) 2024 Alexander Mann-Wahrenberg (basejumpa)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

---

Happy remote switching :-)

Resources used#

  • Raspberry Pi GPIO Python Guide

  • gpiozero - A simple interface to GPIO devices with Raspberry Pi

  • Thread “Using gpiozero on RPI to control pins, but output pins are reset upon script exit, even though state is remembered between runs” at Stack Overflow.

  • gpiozero#707 - Issue “Allow users to disable implicit cleanup”

  • raspberrypi/utils - A collection of scripts and simple applications

  • Setting up Wi-Fi on the Raspberry Pi with nmtui

Bycatches#