In Spring 2025, we hosted a creative and hands-on FemTech workshop where we combined encryption, technology, and nature. Participants worked with Python programming and physical computing to build their own personal artifact: a potted plant that encrypts messages!
The workshop introduced core concepts of encryption, especially the classic Caesar Cipher, and explored how technological artifacts can make invisible or abstract processes tangible and interactive. Through step-by-step coding and hardware exercises, participants learned to build a playful encryption device where the plant determines the encryption key.

🌿 The Artifact: A Potted Plant as an Encryption Key
The artifact consists of a potted plant, a Raspberry Pi Pico, a soil moisture sensor, a toggle switch, a button, and an RGB LED. The moisture level of the soil acts as a “seed” for the Caesar Cipher—determining how many steps each letter in the message is shifted.
- 🌱 The plant’s moisture level is measured and used as the encryption key.
- 🔘 A button is used to activate message input/output.
- 🔁 A toggle switch selects between encryption and decryption.
- 💡 The LED shows the mode—green for encryption and red for decryption.
This interactive setup turns an abstract concept like randomness and seeding into a sensory and engaging experience—combining nature and code in a surprising way.
Elze – as in Elizebeth Friedman

We call the artifact Elze. A name that serves several purposes. It is short for Elizebeth Friedman, one of the pioneering women in modern cryptography, who played a key role in breaking codes during both World Wars and advancing the field. It is also like the old Danish name Else, giving the artifact a local and personal touch. And finally it refers to else, a well-known command in programming languages, a small nod to the coding aspect of the workshop.
🛠️ Workshop Exercises
STep 1: Getting to know each other
We started with a playful icebreaker called Human Bingo, where participants had to move around the room and find someone who:
- had tried coding before
- was considering a tech-related education
- liked coffee ☕
- or had simply taken the bus that day 🚌
This created an open and welcoming atmosphere and helped participants connect with each other before diving into the technical parts.

Participants then installed the Thonny editor, a beginner-friendly Python IDE, and wrote their first program. Each participant was encouraged to personalize their own interview script by editing this example:
# Print statements
print("Hello world")
# Use input and a variable
print("What is your name?")
myName = input()
print("It is good to meet you, " + myName)
# Use a variable and a number (note: convert input to integer!)
print("The length of your name is: " + str(len(myName)))
print("What is your age?")
myAge = input()
print("On your next birthday you will be " + str(int(myAge) + 1) + ".")
# IF and ELSE
print("Do you want me to sing you a birthday song? Please write Yes or No")
answer1 = input()
if answer1 == "Yes":
print("Happy birthday to you, happy birthday to you, happy birthday dear " + myName + ", happy birthday to you!")
else:
print("Okay")
# FOR LOOP
print("Do you want me to say hurra the number of years?")
answer2 = input()
if answer2 == "Yes":
for i in range(int(myAge)):
print("Hurra")
else:
print("Okay")
print("HUUUUUURAAAAAAAA!")
materials and connections
All code examples used in the workshop were made available on:
👉 GitHub.com/SaraBoline/Femtech25S
To build your encryption plant artifact, you’ll need to connect several components to the Raspberry Pi Pico using a breadboard and jumper wires.
We used a Raspberry Pi Pico, connected to components like buttons, an LED, a toggle switch, and a soil moisture sensor.


These components were connected via jumper wires and a breadboard, a tool that lets you build electronic circuits without soldering. For many participants, this setup can feel abstract and unfamiliar, so we made sure to:
- give a walkthrough of the Raspberry Pi Pico layout
- explain what each pin does (power, ground, input/output)
- encourage experimentation by letting participants try different pins
- show them how to change the pin number in the code
This made the breadboard feel less like a mystery and more like a creative prototyping tool.
Step 2: Button & Neopixel
Participants learned how to connect a button to the Raspberry Pi Pico and control an RGB LED using Python. Pressing the button triggered color changes.

from neopixel import Neopixel
from machine import Pin
import time
# Initialize button with pull-up resistor
button = Pin(20, Pin.IN, Pin.PULL_UP)
# Initialize NeoPixel strip
num_pixels = 5 # Adjust for your setup
pixels = Neopixel(num_pixels, 0, 28, "RGB") # Ensure correct GRB order
# Define color sequence
colors = [
(255, 0, 0), # Red
(0, 255, 0), # Green
(0, 0, 255), # Blue
(255, 255, 0), # Yellow
(255, 0, 255) # Magenta
]
color_index = 0 # Start with the first color
def set_color(color):
"""Set all NeoPixels to the given color."""
for i in range(num_pixels):
pixels.set_pixel(i, color)
pixels.show()
# Set initial color
set_color(colors[color_index])
while True:
if not button.value(): # Button pressed (LOW)
print("Button pressed!")
color_index = (color_index + 1) % len(colors) # Cycle to the next color
set_color(colors[color_index])
time.sleep_ms(500) # Debounce delay to avoid multiple detections
Step 3: Switch & Neopixel
We added a toggle switch, allowing participants to change the LED color based on the switch position—introducing state-based logic. At this point we also explained the RGB logic of the code, and asked the participants to choose their own colors for this exercise.

from neopixel import Neopixel
from machine import Pin
import time
#Led light
#num_pixels = 5 # Adjust for your setup
pixels = Neopixel(1, 0, 0, "RGB") # Ensure correct GRB order
# Initialize toggle switch with pull-up resistor
toggle_switch = Pin(16 , Pin.IN, Pin.PULL_UP)
while True:
if toggle_switch.value() == 0: # Switch is pressed (LOW)
#print("Switch is ON")
pixels.set_pixel(0, (0, 255, 0))
pixels.show()
else: # Switch is not pressed (HIGH)
#print("Switch is OFF")
pixels.set_pixel(0, (255, 0, 0))
pixels.show()
time.sleep(0.2) # Delay to prevent constant printingb
Step 4: Switch & Encryption
We connected the switch to our Caesar Cipher logic, letting participants choose whether the system should encrypt or decrypt a message using the toggle switch.

from machine import Pin
import time
# Initialize toggle switch with pull-up resistor
toggle_switch = Pin(16, Pin.IN, Pin.PULL_UP)
# Caesar cipher shift (for encryption and decryption)
shift = 3 # You can change the shift value
# Function for encryption
def encrypt(message, shift):
encrypted_message = ""
for char in message:
if char.isalpha(): # Encrypt only letters
start = ord('a') if char.islower() else ord('A')
encrypted_message += chr((ord(char) - start + shift) % 26 + start)
else:
encrypted_message += char # Keep non-alphabet characters as is
return encrypted_message
# Function for decryption
def decrypt(message, shift):
return encrypt(message, -shift) # Decryption is the reverse of encryption
# Main loop
while True:
# Input message from the user
message = input("Enter a message: ")
if toggle_switch.value() == 0: # Switch is pressed (LOW) -> Encrypt
encrypted_message = encrypt(message, shift)
print("Encrypted message:", encrypted_message)
else: # Switch is not pressed (HIGH) -> Decrypt
decrypted_message = decrypt(message, shift)
print("Decrypted message:", decrypted_message)
time.sleep(0.5) # Delay to prevent constant printing
Step 5: Soil Moisture – Send a Message
Participants read live data from the soil moisture sensor and used it to simulate a message send event.

Firstly the participants connected the soil moisture sensor and use the code below to learn about the values.
from machine import ADC, Pin
import time
# Define ADC pin
soil_moisture = ADC(Pin(28)) # GP26 is ADC0
while True:
value = soil_moisture.read_u16() # Read ADC value (0-65535)
voltage = value * 3.3 / 65535 # Convert to voltage
print(f"Raw Value: {value}, Voltage: {voltage:.2f}V")
time.sleep(1) # Wait 1 second
Then we added the colored pin in order to visualise these values, and furthermore added a feature, to print the message “water the plant” when the moisture value is below a given value.

# Neopixel with potentiometer
from neopixel import Neopixel
from machine import Pin, ADC
import time
# Initialize NeoPixel strip
pixels = Neopixel(5, 0, 0, "RGB") # (num_pixels, state_machine, pin, mode)
# Initialize potentiometer (soil moisture sensor)
adc = ADC(Pin(28, mode=Pin.IN))
# Flag to track if the warning has been printed
warning_printed = False
def map_to_rainbow_color(value):
"""Map ADC value to a color."""
if value > 0 and value < 20000:
return (255, 0, 0) # Red
elif value > 20001 and value < 30000:
return (255, 127, 0) # Orange
elif value > 30001:
return (0, 255, 0) # Green
while True:
low_res = adc.read_u16() # Read sensor value
color = map_to_rainbow_color(int(low_res)) # Get corresponding color
# Set NeoPixel color
pixels.set_pixel(0, color)
pixels.show()
# Print values
print(low_res)
print('#%02x%02x%02x' % color)
# Print "Water your plant!" only once when value drops below 10,000
if low_res < 10000 and not warning_printed:
print("Water your plant!")
warning_printed = True # Set flag so it doesn't print repeatedly
# Reset flag when value rises above 10,000
elif low_res >= 10000:
warning_printed = False # Allow message to print again on next drop
time.sleep_ms(1000) # Wait 1 second
Step 6: Soil Moisture & Encryption – Build the Artifact
In this step, the measured soil moisture was used as a seed for encryption—making each plant produce unique message shifts.
The artifact uses the same connections as the previous with the color LED and the moisture sensor. Then a toggle switch is also added on GP16.
from machine import Pin, ADC
import time
# Toggle swich
toggle_switch = Pin(16, Pin.IN, Pin.PULL_UP)
# ADC pin for soil moisture sensor
soil_moisture = ADC(Pin(28)) # GP26 is ADC0
# Kryptering funktion
def encrypt(message, shift):
encrypted_message = ""
for char in message:
if char.isalpha(): # Encrypt only letters
start = ord('a') if char.islower() else ord('A')
encrypted_message += chr((ord(char) - start + shift) % 26 + start)
else:
encrypted_message += char # Keep non-alphabet characters as is
return encrypted_message
# Dekryptering
def decrypt(message, shift):
return encrypt(message, -shift) # Decryption is the reverse of encryption
# Function to get Caesar cipher shift value based on soil moisture
def get_shift():
value = soil_moisture.read_u16() # Read ADC value (0-65535)
shift = int((value / 65535) * 25) + 1 # Scale to a shift between 1 and 26
print(f"Soil Moisture Value: {value}, Shift: {shift}")
return shift
# Main loop
while True:
message = input("Enter a message: ")
shift = get_shift() # Get shift value based on soil moisture
if toggle_switch.value() == 0: # Switch is pressed (LOW) -> Encrypt
encrypted_message = encrypt(message, shift)
print("Encrypted message:", encrypted_message)
else: # Switch is not pressed (HIGH) -> Decrypt
decrypted_message = decrypt(message, shift)
print("Decrypted message:", decrypted_message)
time.sleep(1) # Delay to prevent rapid polling
Participants have now brought everything together: connecting the plant, button, switch, LED, and code logic into a working artifact that encrypts and decrypts messages.
💬 That “Aha!” Moment
A magical moment happened when participants used their own plant to encrypt a message and let a partner decode it. Suddenly, everything came together—the sensor data, the code, and the physical interface. What was once invisible (like a variable or seed) became real, tactile, and understandable. It was a moment of real learning and excitement.
Step 7: elaborating on ideas
The participants had some time when assembling the artifact and after to think about how the artifact could be elaborated, changed, explored etc. in order to change the interaction or context.
We used a crazy-5 exercice, where the participants stood in two circles and had to discuss and elaborate on ideas on limited time. The only rule for the the exercise was that the participants only were allowed to say “yes and…”- and then elaborate on the other idea or their own. We did it in five rounds of one minute.

To wrap up the artifact we used the concept cards and grouped the participants in groups of four, and they had to fill out, based on the discussion they had, and make som choices about their concept/artifact.