Digital Piano → Home Assistant Picnic Shopping Cart
Build your Picnic shopping cart by playing your digital piano! This project bridges MIDI input from a piano connected to a Raspberry Pi to Home Assistant, allowing each piano key to add a product to your Picnic cart with voice confirmation.
Features
✨ Password Protection: Requires a note sequence or chord before shopping actions are enabled
🎹 Double-Tap Confirmation: Each key must be played twice to prevent accidental additions
🔊 Voice Announcements: Home Assistant announces when system is armed and when products are added via Assist Satellite
⚡ Rate Limiting: Prevents duplicate additions from stuck keys or rapid presses
🔄 Auto-Reconnect: Automatically reconnects if keyboard or Home Assistant disconnects
🛡️ Auto-Disarm: Automatically returns to safe state after inactivity with voice notification
🎵 88-Key Support: Map any MIDI note (0-127) to any Picnic product
Architecture
Digital Piano (USB) → Raspberry Pi (Python) → Home Assistant (WebSocket) → Picnic API
The bridge runs on a Raspberry Pi, reading MIDI events via mido and python-rtmidi, then triggering Home Assistant services (picnic.add_product and assist_satellite.announce) over WebSocket.
Quick Start
Prerequisites
- Hardware: Raspberry Pi 3B+/4/5 with Raspbian OS, digital piano with USB MIDI
- Home Assistant: Running instance with Picnic and Assist Satellite integrations configured
- Python: 3.9+ (pre-installed on Raspbian Bookworm)
Installation
-
Clone the repository:
git clone <your-repo-url> ~/DigitalPianoPicnic cd ~/DigitalPianoPicnic -
Install system dependencies:
sudo apt-get update sudo apt-get install -y libasound2-dev python3-pip -
Install Python dependencies (using virtual environment):
python3 -m venv venv source venv/bin/activate pip3 install -r requirements.txt -
Configure the application:
# Copy example configs cp config/app.yaml.example config/app.yaml cp config/mapping.yaml.example config/mapping.yaml # Edit configs with your settings nano config/app.yaml # Set HA URL and device ID nano config/mapping.yaml # Map notes to products # Set your Home Assistant token echo 'export HA_TOKEN="your-long-lived-token-here"' >> ~/.bashrc source ~/.bashrc -
Test manually:
source venv/bin/activate # Test mode (no Home Assistant required, just keyboard/MIDI): python3 src/bridge.py --test # Real mode (requires HA_TOKEN and Home Assistant connection): python3 src/bridge.pyTest mode:
- Tests MIDI input, arming sequence, double-tap, and rate limiting
- Fakes Home Assistant calls (no actual products added)
- Perfect for verifying keyboard functionality
Real mode:
- Play the arming sequence (default: C-D-E)
- Play a mapped key twice quickly
- Verify product is added and announced
-
Install as system service:
# Edit service file with your token sudo nano deployment/midi-ha.service # Install and start sudo cp deployment/midi-ha.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable midi-ha.service sudo systemctl start midi-ha.service # Check status sudo systemctl status midi-ha.service sudo journalctl -u midi-ha.service -f
Configuration
Arming Sequence
Edit config/app.yaml to set your password:
arming:
enabled: true
sequence: [60, 62, 64] # C, D, E (Middle C = MIDI note 60)
sequence_timeout_ms: 3000
MIDI Note Reference: C4=60, C#4=61, D4=62, D#4=63, E4=64, F4=65, F#4=66, G4=67, G#4=68, A4=69, A#4=70, B4=71, C5=72...
Product Mapping
Edit config/mapping.yaml to assign products to keys:
notes:
60: # Middle C
product_id: s1018231
product_name: "Picnic cola zero"
amount: 1
Find Picnic product IDs:
Option 1: Use the search tool (recommended)
# Install the optional tool
pip install python-picnic-api
# Set credentials (secure method)
export PICNIC_USERNAME='your@email.com'
export PICNIC_PASSWORD='yourpassword'
# Search for products
python3 tools/search_products.py "coca cola zero"
python3 tools/search_products.py --interactive
# See tools/README.md for full documentation
Option 3: Manual Lookup via Home Assistant
- Open Picnic app/website
- Add product to cart
- Check Home Assistant Developer Tools → States →
sensor.picnic_cart_items - Look for
product_idin the state attributes
Find Picnic config_entry_id (REQUIRED):
- Go to Home Assistant → Settings → Devices & Services
- Click on the Picnic integration
- Copy the ID from the URL after
/integration/(e.g.,01JEN4FWWJ123ABCDEF456789) - Add it to
config/mapping.yamlunderdefaults.config_entry_id
Update config/mapping.yaml:
defaults:
config_entry_id: "01JEN4FWWJ123ABCDEF456789" # From Picnic integration URL
Voice Announcements
Find your Assist Satellite device ID:
- Go to Home Assistant → Settings → Devices & Services
- Find your Assist Satellite device
- Click on it and copy the device ID from the URL
Update config/app.yaml:
announce:
enabled: true
device_id: 4f17bb6b7102f82e8a91bf663bcb76f9
message_template: "{product_name} was added to basket"
Usage
- Arm the system: Play the password sequence (default: C-D-E)
- Add products: Play any mapped key twice within 800ms
- Listen: Home Assistant announces the product name
- Auto-disarm: System disarms after 60 seconds of inactivity
Tips
- Use a memorable melody as your password (4+ notes recommended)
- Map frequently-used products to convenient keys (white keys near middle C)
- Adjust
double_tap_window_msif you have difficulty with timing - Set
disarm_after_add: truefor extra security (requires re-arming after each product)
Troubleshooting
No MIDI ports detected
# List USB devices
lsusb
# List MIDI ports
amidi -l
# Test MIDI input
aseqdump -p <port>
WebSocket connection fails
# Test connectivity
curl -v ws://homeassistant.local:8123/api/websocket
# Use IP address if .local doesn't resolve
# Update config/app.yaml with: ws://192.168.1.100:8123/api/websocket
Service won't start
# Check logs
sudo journalctl -u midi-ha.service -n 50 --no-pager
# Check HA_TOKEN is set in service file
sudo systemctl cat midi-ha.service
# Test manually
HA_TOKEN="your-token" python3 src/bridge.py
Products not adding
- Verify Picnic integration is configured in Home Assistant
- Check product IDs are correct (case-sensitive)
- Review logs:
sudo journalctl -u midi-ha.service -f - Test service call in HA Developer Tools
Announcements not working
- Verify Assist Satellite device ID is correct
- Test announcement manually in HA Developer Tools
- Check device is online and responding
Piano disconnected
Symptom: MIDI connection lost in logs
Solution: The system automatically tries to reconnect every 5 seconds. Just plug the keyboard back in or power it on.
Security: The arming state is automatically reset to DISARMED when the device disconnects, so you'll need to re-enter your password sequence after reconnection.
To change reconnect delay, edit config/app.yaml:
runtime:
midi_reconnect_delay_sec: 10 # Wait 10 seconds between retries
Development
Project Structure
DigitalPianoPicnic/
├── config/
│ ├── app.yaml.example # Main config template
│ └── mapping.yaml.example # Product mapping template
├── src/
│ ├── midi.py # MIDI input handling
│ ├── ha_client.py # Home Assistant WebSocket client
│ └── bridge.py # Main application logic
├── deployment/
│ └── midi-ha.service # Systemd service file
├── docs/
│ └── plan.md # Detailed project plan
├── requirements.txt # Python dependencies
├── .env.example # Environment variables template
└── README.md # This file
Testing Modules Independently
Test MIDI input:
python3 src/midi.py
Test HA client:
export HA_URL="ws://homeassistant.local:8123/api/websocket"
export HA_TOKEN="your-token"
python3 src/ha_client.py
Test keyboard/MIDI functionality (no HA required):
python3 src/bridge.py --test
Test full bridge (requires HA):
python3 src/bridge.py
Adding Features
See the following documentation:
docs/plan.md- Complete roadmap and architecture detailsdocs/ARMING_ANNOUNCEMENTS.md- Voice announcement configurationTEST_MODE.md- Testing without Home AssistantQUICKSTART.md- Quick setup guide
Security
- Never commit
config/app.yaml,config/mapping.yaml, or.envfiles - Store
HA_TOKENin environment variables or systemdEnvironmentFile - Use a non-trivial arming sequence (4+ notes)
- Enable
disarm_after_addfor high-security scenarios - Run service as non-root user (default:
pi)
Contributing
Contributions welcome! Please:
- Update
docs/plan.mdfor architectural changes - Add logging at appropriate levels
- Update config examples if adding options
- Test on real hardware before submitting PR
License
MIT License - see LICENSE file for details
Credits
- MIDI: mido and python-rtmidi
- Home Assistant: WebSocket API
- Picnic: Integration
Support
For issues or questions:
- Check
docs/plan.mdfor detailed documentation - Review logs:
sudo journalctl -u midi-ha.service -f - Open an issue on GitHub
Made with ❤️ for lazy grocery shopping 🎹🛒