A Raspberry Pi-based barcode scanner interface for Grocy inventory management. This application runs on a Raspberry Pi with a USB barcode scanner and a 7" touchscreen display, allowing you to quickly add or deduct stock by scanning barcodes.
- Touch-friendly UI: Large buttons optimized for 7" touchscreen displays
- Three Actions: Add to stock, open product, or deduct from stock with a single tap
- Visual Feedback: Shows product name, image, and updated stock quantity on success
- Error Handling: Clear error messages when barcodes are not found
- Easy Configuration: Full-screen configuration page for Grocy host and API key
- USB Barcode Scanner Support: Works with any USB barcode scanner that emulates keyboard input
- Customizable UI: Easy theme customization via
theme.py- change colors, fonts, and sizes
- Raspberry Pi (Zero 2W, 3B, 4B, or 5)
- 7" Touchscreen Display (official Raspberry Pi display recommended)
- USB Barcode Scanner (keyboard emulation mode)
- Raspberry Pi OS Lite 64-bit (recommended)
- Python 3.7 or higher
This guide covers installation on Raspberry Pi OS Lite 64-bit. The application requires an X server to run the GUI, which we'll install and configure.
- Download Raspberry Pi OS Lite (64-bit) from raspberrypi.org
- Use Raspberry Pi Imager to flash the OS to your SD card
- During the imaging process, configure:
- SSH: Enable SSH access (recommended)
- WiFi: Configure WiFi credentials (optional but recommended)
- User: Set up your user account (default is
pi)
- Insert the SD card into your Raspberry Pi and boot it
Connect to your Raspberry Pi via SSH or directly, then run:
# Update package list and upgrade system
sudo apt-get update
sudo apt-get upgrade -y
# Install X server and required dependencies
sudo apt-get install -y \
xserver-xorg \
xinit \
openbox \
python3 \
python3-pip \
python3-venv \
python3-tk \
python3-pil \
python3-pil.imagetk \
libxss1 \
libgconf-2-4 \
xinput \
x11-xserver-utils \
x11-xserver-utils \
git
# Verify X server installation
which XNote: The xinit package provides the startx command, which we'll use to start the X server.
# Navigate to home directory
cd ~
# Clone the repository
git clone https://github.com/JesseFPV/grocy_scanner.git
# Navigate into the project directory
cd grocy_scannerNote: If you're using a fork or different repository, adjust the URL accordingly.
# Create a virtual environment
python3 -m venv venv
# Verify venv was created
ls -la venv/bin/pythonWhy use a virtual environment?
- Raspberry Pi OS uses an "externally managed" Python environment
- A virtual environment isolates project dependencies
- Prevents conflicts with system Python packages
# Activate the virtual environment
source venv/bin/activate
# Upgrade pip (recommended)
pip install --upgrade pip
# Install project dependencies
pip install -r requirements.txt
# Verify installation
pip listYou should see packages like requests and Pillow installed in the virtual environment.
Before setting up auto-start, let's test that everything works:
# Make sure venv is activated
source venv/bin/activate
# Test Tkinter (should work without errors)
python3 -c "import tkinter; print('Tkinter works')"
# Start X server in background
startx &
# Wait a few seconds for X server to initialize
sleep 3
# Set DISPLAY variable and start the application
export DISPLAY=:0
python main.pyThe application should start and show the configuration page. Press Escape to exit fullscreen.
Troubleshooting:
- If you get "no display name and no $DISPLAY", make sure you've set
export DISPLAY=:0 - If
startxis not found, ensurexinitis installed:sudo apt-get install xinit - If the application doesn't start, check logs:
journalctl -u intake.service -n 50(after setting up the service)
On first run, the application will prompt you to enter:
- Grocy Host: The URL of your Grocy instance (e.g.,
https://grocy.example.com) - API Key: Your Grocy API key (found in Grocy under Settings > API keys)
Configuration is saved to config.json in the project directory. This file is automatically ignored by git to protect your API key.
To automatically start Intake when your Raspberry Pi boots, we'll create a systemd service that starts the X server and the application.
Openbox is a lightweight window manager that we'll use to run the application in kiosk mode:
sudo apt-get install -y openboxCreate the Openbox autostart script that will launch Intake:
# Create Openbox config directory
mkdir -p /home/pi/.config/openbox
# Create autostart script
nano /home/pi/.config/openbox/autostartAdd the following content:
#!/bin/sh
# Disable screen blanking
xset -dpms
xset s off
xset s noblank
# Start Intake app
cd /home/pi/grocy_scanner
source venv/bin/activate
exec python main.pyMake it executable:
chmod +x /home/pi/.config/openbox/autostartCreate a script that starts X server with Openbox on tty1:
# Create the startup script
sudo nano /usr/local/bin/start-intake.shAdd the following content (adjust paths if your username or project location differs):
#!/usr/bin/env bash
# Intake kiosk startup script
# Starts X on tty1 and launches the Intake Tkinter app
set -e
APP_DIR="/home/pi/grocy_scanner"
VENV_DIR="$APP_DIR/venv"
LOG_FILE="$APP_DIR/intake.log"
# Log helper
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
log "==== Intake startup ===="
# Safety: ensure correct user
if [ "$(id -u)" = "0" ]; then
log "ERROR: Script must not run as root"
exit 1
fi
# Ensure app directory exists
if [ ! -d "$APP_DIR" ]; then
log "ERROR: App directory not found: $APP_DIR"
exit 1
fi
cd "$APP_DIR"
# Ensure virtual environment exists
if [ ! -f "$VENV_DIR/bin/python" ]; then
log "ERROR: venv not found at $VENV_DIR"
exit 1
fi
log "Activating virtual environment"
source "$VENV_DIR/bin/activate"
# Export minimal environment for X / Tkinter
export HOME="/home/pi"
export USER="pi"
export DISPLAY=":0"
export XAUTHORITY="$HOME/.Xauthority"
# Create Xauthority if missing
touch "$XAUTHORITY"
chmod 600 "$XAUTHORITY"
log "Starting X via startx on tty1"
# Start X and keep VT
exec startx /usr/bin/openbox-session -- :0 vt1 -keepttyMake the script executable and set proper ownership:
sudo chmod +x /usr/local/bin/start-intake.sh
sudo chown pi:pi /usr/local/bin/start-intake.shCreate a systemd service file:
sudo nano /etc/systemd/system/intake.serviceAdd the following content (adjust User= if your username is different):
[Unit]
Description=Intake Application (kiosk)
After=getty@tty1.service network.target
Wants=getty@tty1.service
[Service]
User=pi
WorkingDirectory=/home/pi/grocy_scanner
Environment=HOME=/home/pi
Environment=DISPLAY=:0
StandardInput=tty
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
ExecStart=/usr/local/bin/start-intake.sh
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.targetImportant notes about this service configuration:
TTYPath=/dev/tty1- Runs on virtual terminal 1 (the physical display)After=getty@tty1.service- Waits for tty1 to be readyRestart=on-failure- Only restarts on failure, not on normal exitStandardInput=tty- Connects to the terminal for proper X server operation
# Reload systemd to recognize the new service
sudo systemctl daemon-reload
# Enable the service to start on boot
sudo systemctl enable intake.service
# Start the service now (don't wait for reboot)
sudo systemctl start intake.service
# Check the service status
sudo systemctl status intake.serviceThe service should now be running. After rebooting your Raspberry Pi, Intake will start automatically.
# View service status
sudo systemctl status intake.service
# View service logs
sudo journalctl -u intake.service -f
# Stop the service
sudo systemctl stop intake.service
# Start the service
sudo systemctl start intake.service
# Restart the service
sudo systemctl restart intake.service
# Disable auto-start (but keep service file)
sudo systemctl disable intake.service- Start the application - The UI will appear in fullscreen mode
- Select an action - Tap one of three options:
- Add to Stock: Add a new product to inventory
- Open Product: Mark a product as opened (e.g., opening a bottle of cola)
- Deduct from Stock: Remove/consume a product completely
- Scan a barcode - Use your USB barcode scanner to scan a product barcode
- View results - Success shows product info and new stock level; errors show clear messages
Escape: Exit fullscreen mode⚙️ Configbutton: Access configuration page (full-screen view)
Most USB barcode scanners work in "keyboard emulation" mode, which means they send scanned data as if typed on a keyboard. The application captures this input automatically.
If your scanner doesn't work automatically, you may need to:
- Check that the scanner is recognized:
lsusbordmesg | tail - Ensure the scanner is in keyboard emulation mode (check scanner manual)
- Test scanner input:
cat /dev/input/event*(may require sudo)
-
Check service status:
sudo systemctl status intake.service
-
View systemd logs for errors:
sudo journalctl -u intake.service -n 100 --no-pager
-
Check application log file (most important!):
# View the log file cat /home/pi/grocy_scanner/intake.log # Or follow it in real-time tail -f /home/pi/grocy_scanner/intake.log
This log file will show you exactly where the script is failing.
-
Verify paths are correct:
# Check project directory exists ls -la /home/pi/grocy_scanner # Verify venv exists ls -la /home/pi/grocy_scanner/venv/bin/python # Ensure script is executable ls -la /usr/local/bin/start-intake.sh
-
Test script manually (as pi user):
sudo -u pi /usr/local/bin/start-intake.sh
Note: This will block your terminal. Press Ctrl+C to stop it.
-
Test X server separately:
# As pi user, test X server sudo -u pi X -nolisten tcp :0 & sleep 3 sudo -u pi DISPLAY=:0 xdpyinfo
-
Common issues and fixes:
Issue: Permission denied
# Fix script permissions sudo chmod +x /usr/local/bin/start-intake.sh sudo chown pi:pi /usr/local/bin/start-intake.shIssue: X server already running
# Kill existing X server sudo pkill X # Then restart service sudo systemctl restart intake.service
Issue: Virtual environment not found
# Recreate venv cd /home/pi/grocy_scanner python3 -m venv venv source venv/bin/activate pip install -r requirements.txt
Issue: Tkinter not available
# Reinstall python3-tk sudo apt-get install --reinstall python3-tk
Error: "no display name and no $DISPLAY"
- Solution: The DISPLAY variable must be set. Ensure your startup script includes
export DISPLAY=:0 - If testing manually, use:
export DISPLAY=:0before runningpython main.py
X server not starting
This is common when running via SSH. The solution is to use startx with Openbox on a virtual terminal (tty1).
Solution: Use startx with Openbox (as documented in installation)
# Ensure Openbox is installed
sudo apt-get install openbox
# Ensure autostart script exists and is executable
chmod +x /home/pi/.config/openbox/autostart
# Test manually (will block SSH session)
sudo -u pi startx /usr/bin/openbox-session -- :0 vt1 -keepttyIf you see "Permission denied" for /dev/tty0:
- This is normal when running via SSH
- The service configuration uses
TTYPath=/dev/tty1which works correctly - Make sure the service is configured as shown in Step 8.4
Verify Openbox autostart:
# Check autostart script exists
ls -la /home/pi/.config/openbox/autostart
# View autostart content
cat /home/pi/.config/openbox/autostart- Ensure the scanner is in keyboard emulation mode
- Check USB connection:
lsusb - Verify scanner is recognized:
dmesg | tail
- Verify your Grocy host URL is correct (include https://)
- Check that your API key is valid
- Ensure your Raspberry Pi can reach the Grocy server (network connectivity)
- Test connectivity:
ping grocy.example.com(replace with your Grocy host)
Error: "externally-managed-environment"
- This means you need to use a virtual environment
- Follow Step 4 to create and activate the venv
- Always activate venv before running:
source venv/bin/activate
Packages not found
- Ensure venv is activated:
source venv/bin/activate - Reinstall packages:
pip install -r requirements.txt - Verify packages:
pip list
To update Intake to the latest version:
# Stop the service
sudo systemctl stop intake.service
# Navigate to project directory
cd ~/grocy_scanner
# Pull latest changes
git pull
# Activate venv and update dependencies
source venv/bin/activate
pip install -r requirements.txt --upgrade
# Restart the service
sudo systemctl start intake.serviceThe UI can be easily customized by editing theme.py. You can change:
- Colors (background, buttons, status messages)
- Fonts (family, sizes, weights)
- Sizes and spacing (button sizes, padding, image sizes)
- Window settings (fullscreen, title)
See UI_CUSTOMIZATION.md for detailed instructions and examples.
To use a different theme, edit ui.py and change the import:
# Default theme
from theme import Theme
# Portal/Aperture Science theme (modern, futuristic)
from themes.portal_theme import PortalTheme as Theme
# Or use an example theme
from themes.light_theme import LightTheme as Theme
from themes.large_font_theme import LargeFontTheme as Theme
from themes.dark_blue_theme import DarkBlueTheme as ThemeNote: The Portal theme is currently active by default and uses the Rajdhani font for a modern, futuristic look.
The project structure:
main.py: Entry point and application initializationconfig.py: Configuration managementgrocy_api.py: Grocy API clientscanner.py: USB barcode scanner input handlingui.py: Touch-friendly GUI interfacetheme.py: UI theme configuration (colors, fonts, sizes)themes/: Example theme files
[Add your license here]
Contributions are welcome! Please feel free to submit a Pull Request.