Introduction: Proximity Switch

About: I work in assistive technology in a public school system in Virginia. I am also a licensed speech-language pathologist in the state of Virginia.

Proximity sensors are in many kinds of technology, like sinks, water fountains, paper towel dispensers, and automatic doors that activate without having to be touched. This same technology can help individuals with disabilities who struggle to use interfaces such as touchscreens, computers, keyboards, and traditional computer mice. These sensors can send a signal to a computer or tablet to activate an icon (enter keypress or left mouse click) or move to the next icon (tab keypress) when they detect that something is close to it.

In the past year, I have been on a journey with this technology that resulted in a $25, highly customizable proximity switch that gives access to computers and tablets without having to touch them using an access method called switch scanning. Commercially available proximity switches and adaptors that connect them to computers or tablets can cost hundreds of dollars and have limited customization options in terms of both appearance and function.

If you're anything like me, you might be thinking that you could never make something like that because you don't know how to code or solder or 3D print.

Do you know how to copy and paste?

Do you know how to left and right click on files and links?

Do you know how to get to your download folder?

Congratulations, you have the skills you need to make a proximity switch!

(The 3-D printing is optional. Making a case for the electronics can keep the wires in place better, protect them, and make them look nicer, but it's not required for them to work.)

Use a printed circuit board (PCB) and a proximity sensor to create a customizable proximity switch that can activate any keypress. No soldering is required or coding is required! You need to know how to download and unzip files, copy, and paste. That's it!


Please leave feedback telling me how to make this better!


Supplies

Adafruit QT Py RP2040 printed circuit board

VCNL 4040 proximity sensor

STEMMA QT cable to connect the proximity sensor to the printed circuit board

USB A to USB C cable that transfers power AND data (can also be easily purchased from Amazon, just check the listing to make sure it specifies that the cable transfers power AND data)

OPTIONAL


Modular hose for mounting (the QT Py 2040 is small, but not small enough to thread through modular hose)

See attached file for a clamp with an opening that 1/4 inch modular hose can fit into. Recommended material is ABS.

Industrial twist ties (can loop around the outside of the modular hose to secure the wires and housing)


Step 1: Plug Everything In

Connect the VCNL 4040 proximity sensor to the QT Py using the STEMMA cable (black cable with the four different colored wires exposed at the ends)

  1. Plug one end into the smaller connector on the QT Py (the word BOOT is written above it) and the other into either connector on the VCNL 4040 proximity sensor (both work the same).

Plug the QT Py into your computer using the metal USB-C cable (small oval end goes into the QT Py, the larger rectangular end goes into your computer).

For Mac users: You might need a USB adaptor, but this setup has been tested and works on Mac!

Please note that the little rectangle with two holes in it in the middle of the VCNL4040 is the actual sensor and needs to be uncovered and facing the direction of the movement it's supposed to detect to take readings!

Step 2: Put the QT Py Into Bootloader Mode

  1. connect the QT-Py to your computer with the USB cable.
  2. press and hold the Boot button.
  3. press and release the Reset button.
  4. release the Boot button.

Make sure it worked!


•Look on the left where your list of drives are

•You should see a drive that says RP1-RP2 around where you’d see a USB drive pop up when you plug one of those in.

Step 3: Troubleshoot If Needed

  1. Make sure you are holding down the boot button WHILE you hold down AND release the reset button. Don't release the boot button until AFTER you've pressed and released the reset button.
  2. If you don't see the RPI-RP2 drive, make sure you have a USB cable that transfers power AND data. You can't tell just by looking! If you're not positive that your cable transfers both data AND power, try another cable.
  3. Unplug and replug in your STEMMA QT cables if needed. They can get unseated.

Step 4: Download Circuit Python

  1. Go to https://circuitpython.org/board/adafruit_qtpy_rp2040/
  2. You need the most recent version, which was 9x at the time of making this tutorial. Make sure to note the version number, because you'll need to download the corresponding files later!
  3. Click, "Download .UF2 now"

Step 5: Put CircuitPython on QT Py

•Open your downloads folder

•Find the file adafruit-circuitpython-adafruit_metro_rp2040-en_US-9.1.3.uf2 (it will probably be at the top for you, and the numbers at the end of the file name will reflect the most current version number of Circuit Python)

•Click and drag that file down to RP1-RP2, or copy and paste

•You can also right click, go to “send to,” and select RP1-RP2

•The name of the drive will go away, it will beep, and the name of the drive will reappear as CIRCUITPY

Step 6: Download File Libraries

•Download the Circuit Python libraries from https://circuitpython.org/libraries

  1. Scroll down a little to see the bundle. Keep in mind that Circuit Python is always updating, so the version number will be different for you. The file name reflects the version number, so that will also be different for you than in my screenshots and videos. The process is still the same!
  2. Make sure it matches the version of Circuit Python you downloaded before.

•Open your downloads file and find adafruit-circuitpython-bundle-9.x-mpy-20240910 (it will probably be at the top of the folder, and remember, the numbers at the end of the file name will be different for you)

•Unzip it!

Step 7: Put Libraries on QT Py

•Using the search function in Windows Explorer, search for the following library inside of the adafruit-circuitpython-bundle-9.x-mpy-20240910 folder (again, different numbers at the end of the file name for you) by copying and pasting the library name in bold italics below into the search bar :

  1. Adafruit_vcnl4040.mpy

•Drag that library to your CIRCUITPY drive and put it in the lib folder

  1. Make sure you put it inside the lib folder! The computer will be looking for it in that specific location
  2. You can also copy (ctrl + c) and paste (ctrl + v) the files and folders to the lib drive on CIRCUITPY

•Repeat that process for the following items by copying and pasting the library names in bold italics belows:

  1. adafruit_bus_device (a folder)
  2. adafruit_register (a folder)
  3. adafruit_hid (a folder)
  4. neopixel.mpy

NOTE: There are two files called neopixel.mpy. One is 1 KB in size and one is 2 KB in size. You need the one that is 2 KB in size. See the screenshot for help.

Step 8: Put Code on QT Py

  1. Download the code.py file below this step in the Instructable.
  2. Go to your download folder.
  3. Click and drag the file down to CIRCUITPY, or copy and paste it. Tell it to replace the current code.py with the one you downloaded.
  4. Make sure you don't put it in the lib folder like we did above!
  5. Make sure it's named code.py with no period at the end. The computer will be looking for that specific file name.

Attachments

Step 9: Use the Interface to Customize Your Switch

https://webinter.lcps.org/General/AssistiveTechnology/QT_Py_Config_Tool.html

  1. Click the link above to get to the interface you need to customize your switch.
  2. Make the changes in the interface to customize how the switch works. An explanation of each setting is below.
  3. Click the download button. It will download a file called config.json
  4. Navigate to your downloads folder
  5. Copy and paste the config.json file to the CIRCUITPY drive just as we did with the code!


Single key press: Choose which, if any, key you want your switch to activate.

Mouse action: Choose which, if any, mouse action you want to switch to perform.

Proximity Threshold: This sensor doesn't use units of measurement for distance, so the numbers are somewhat arbitrary. However, the bigger the number, the bigger the movement you need to make to activate it.

Loop delay: This is how often you want the sensor to check if anything moved closer or further away. The shorter the time, the more often it will check. These units are seconds, and you can use decimals. The default is every quarter of a second.

Debounce time: This keeps the switch from being activated several times in a row by accident. A smaller number means your switch will activate faster.

Hold key until proximity changes: If you're holding down a key, like to run in a video game, you can tell the switch to hold the key down too until the proximity changes. Otherwise, it will immediately release the key to simulate pressing down a button and then lifting your finger.

Neopixel feedback: This is the little light on the QT Py. You can use RGB to change the color. Just go to https://www.rapidtables.com/web/color/RGB_Color.html and pick the color you want. Then you can type the same three numbers in the text box to get the light to shine that color.

Enable on/off switch: The little boot button located on the QT Py RP2040 labeled "BOOT" used during setup can be repurposed as an on and off switch.

Step 10: Try It Out!

The light on the QT Py RP2040 should be red. That means the switch is off. The boot button we used at the beginning of this process is now an on-off switch. Press it, and the light should change to green. Your switch is now set to a left mouse click!

Step 11: Download Mu Editor to Troubleshoot and Customize (Optional)

•Get directions for how to download Mu Editor from https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor

•Get Mu Editor from https://codewith.mu

•Choose Circuit Python when prompted at start-up

If your switch is plugged it and set up, it should automatically open up the code. Click serial mode to see exactly what your switch is doing second by second!

This can also give you error messages that you can copy and paste into AI for additional troubleshooting if needed, although be aware that AI is currently not very proficient with CircuitPython.


When you plug in your switch, it will automatically turn on. The light on the QT Py RP2040 will flash green whenever it activates and the keypress will occur.

Step 12: Customize the Code Even Further With the Json File

The interface in step 9 creates a file called a json file that you can download and put on the QT Py. This changes how the switch works without directly changing the code. You can interact directly with the config.json file if you want settings that aren't included on the interface, such as a different keypress.

Think of config.json as your switch’s instruction sheet. It tells the switch:

  1. how sensitive it should be
  2. which key it should press
  3. how fast it reacts
  4. whether the built-in NeoPixel light is on
  5. whether the switch is currently ON or OFF

You can safely change these settings without breaking the code, as long as you keep the formatting the same.

How to Edit config.json

  1. Plug your QT Py RP2040 into your computer
  2. The CIRCUITPY drive will appear
  3. Open the file named config.json

Recommended:

Open it using Mu Editor, since that’s what you already use for code.py.

Other options:

  1. Windows: Notepad
  2. Mac: TextEdit (make sure it is in Plain Text mode: Format → Make Plain Text)

⚠️ Be careful not to delete commas, brackets, or quotation marks unless you are intentionally changing a value.

What Each Setting Does

proximity_threshold

This controls how much the sensor reading must change before the switch activates.

  1. Lower number → more sensitive (small movements trigger it)
  2. Higher number → less sensitive (requires bigger movement)

Examples:

  1. 5 = very sensitive
  2. 10 = moderate (default)
  3. 20 = less sensitive

key_action

This controls what key the switch presses.

Most users will only need a single key press.

Example:

"key_action": {
"type": "single_key",
"keys": ["TAB"]
}

To change the key, replace "TAB" with another key name, such as:

  1. "SPACE"
  2. "ENTER"
  3. "UP_ARROW"
  4. "LEFT_ARROW"
  5. "A" (for typing a letter)

Make sure:

  1. The key name is in ALL CAPS
  2. It stays inside quotation marks " "

key_press_duration_seconds

How long the key is held down before being released.

  1. 0.1 = quick tap (recommended)
  2. 0.5 = half-second press
  3. 1.0 = one full second

Most users should leave this at 0.1.

loop_delay_seconds

How often the switch checks the sensor.

  1. Smaller number → more responsive
  2. Larger number → steadier and more forgiving of involuntary movement

Examples:

  1. 0.1 = very responsive
  2. 0.25 = stable default

only_closer_trigger

Controls when the switch activates.

  1. true
  2. The switch activates only when something moves closer to the sensor
  3. (recommended for most users)
  4. false
  5. The switch activates when something moves closer OR farther away

enable_debug_prints

Controls messages in the Mu Editor Serial Console.

  1. true → shows live sensor readings (useful for troubleshooting)
  2. false → keeps things quiet (recommended for everyday use)

enable_on_off_switch

Turns the boot button into an ON/OFF switch.

"enable_on_off_switch": true
  1. When OFF, the switch will not press keys
  2. The OFF state is remembered even if the device is unplugged
  3. Press the boot button to turn it back ON

This is a safety feature and is recommended.

NeoPixel Settings

The built-in NeoPixel shows the current state of the switch.

enable_neopixel_feedback

  1. true → NeoPixel shows ON/OFF status
  2. false → NeoPixel stays off

on_state_neopixel_color_rgb

off_state_neopixel_color_rgb

These control the NeoPixel colors.

Example:

"on_state_neopixel_color_rgb": [0, 255, 0],
"off_state_neopixel_color_rgb": [255, 0, 0]
  1. Green = ON
  2. Red = OFF

Each color is written as:

[Red, Green, Blue]

Values range from 0 (off) to 255 (full brightness).

Example config.json

Here’s an example that:

  1. Uses the SPACE key
  2. Is more sensitive
  3. Shows ON/OFF status with the NeoPixel
  4. Keeps debug messages off
{
"proximity_threshold": 5,
"key_press_duration_seconds": 0.1,
"loop_delay_seconds": 0.25,
"only_closer_trigger": true,
"enable_debug_prints": false,
"enable_neopixel_feedback": true,
"key_action": {
"type": "single_key",
"keys": ["SPACE"]
},
"enable_on_off_switch": true,
"on_state_neopixel_color_rgb": [0, 255, 0],
"off_state_neopixel_color_rgb": [255, 0, 0]
}

Saving Your Changes

  1. Save the config.json file
  2. The QT Py will automatically restart
  3. Your switch will immediately use the new settings

If debug prints are enabled, you’ll see confirmation in the Mu Editor Serial Console.