Update DEVELOPMENT.md with Docker bind mount workflow
- Replace symlink instructions with Docker bind mount setup (primary method) - Add clear guidance on when to restart vs reload integration - Document that Python changes require full restart, YAML only needs reload - Add comprehensive troubleshooting section for common issues - Include performance notes about 15-50x caching improvement - Add code quality standards and pre-commit checks - Clarify symlink limitations in Docker environments
This commit is contained in:
+241
-51
@@ -4,9 +4,37 @@
|
|||||||
|
|
||||||
This repository is set up for active development while being used in a running Home Assistant instance.
|
This repository is set up for active development while being used in a running Home Assistant instance.
|
||||||
|
|
||||||
### Recommended Setup: Symlink Development
|
### Recommended Setup: Docker Bind Mount
|
||||||
|
|
||||||
For active development, symlink this repository into Home Assistant's `custom_components` directory:
|
For Docker-based Home Assistant installations, use a bind mount to link this repository directly into your container. This is the cleanest approach for active development.
|
||||||
|
|
||||||
|
**Add this volume to your Docker run command or docker-compose.yml:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Docker run example
|
||||||
|
docker run ... \
|
||||||
|
-v /path/to/spotify-voice-assistant/custom_components/spotify_search:/config/custom_components/spotify_search:ro \
|
||||||
|
...
|
||||||
|
|
||||||
|
# docker-compose.yml example
|
||||||
|
services:
|
||||||
|
homeassistant:
|
||||||
|
volumes:
|
||||||
|
- /path/to/spotify-voice-assistant/custom_components/spotify_search:/config/custom_components/spotify_search:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- ✅ Edit files in your development repository
|
||||||
|
- ✅ Changes immediately reflected (after restart/reload)
|
||||||
|
- ✅ Develop, test, and commit from one location
|
||||||
|
- ✅ No file duplication or sync issues
|
||||||
|
- ✅ Read-only mount (`:ro`) protects your source files
|
||||||
|
|
||||||
|
**Note:** You'll need to recreate/restart your container after adding the bind mount.
|
||||||
|
|
||||||
|
### Alternative: Symlink Development (Non-Docker or Host Config)
|
||||||
|
|
||||||
|
If you have direct filesystem access to your Home Assistant config directory:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Remove existing installation (if using HACS version)
|
# Remove existing installation (if using HACS version)
|
||||||
@@ -17,58 +45,100 @@ ln -s /path/to/your/spotify-voice-assistant/custom_components/spotify_search \
|
|||||||
/path/to/homeassistant/config/custom_components/spotify_search
|
/path/to/homeassistant/config/custom_components/spotify_search
|
||||||
```
|
```
|
||||||
|
|
||||||
**Benefits:**
|
**Important for Docker:** If using symlinks with Docker, ensure the symlink target path is accessible from inside the container (either mounted or within the config volume).
|
||||||
- ✅ Edit files in your development repository
|
|
||||||
- ✅ Changes immediately affect running Home Assistant (after restart)
|
|
||||||
- ✅ Develop, test, and commit from one location
|
|
||||||
- ✅ No file duplication or sync issues
|
|
||||||
|
|
||||||
### Development Workflow
|
### When to Restart vs Reload
|
||||||
|
|
||||||
1. **Make Changes**
|
Understanding when you need to restart Home Assistant vs just reloading the integration:
|
||||||
```bash
|
|
||||||
cd /path/to/your/spotify-voice-assistant
|
|
||||||
# Edit files in custom_components/spotify_search/
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Test Changes**
|
**Full Restart Required:**
|
||||||
```bash
|
- Python code changes (`__init__.py`)
|
||||||
# Restart Home Assistant
|
- Manifest changes (`manifest.json`)
|
||||||
docker restart homeassistant
|
- Adding/removing the integration
|
||||||
|
- First-time setup
|
||||||
|
|
||||||
# Watch logs
|
**Reload Integration Only:**
|
||||||
docker logs -f homeassistant | grep spotify_search
|
- Service definition changes (`services.yaml`)
|
||||||
```
|
- Go to Developer Tools > YAML > Reload "Core Configuration"
|
||||||
|
|
||||||
3. **Commit Changes**
|
**No Action Required:**
|
||||||
```bash
|
- Documentation changes (README.md, DEVELOPMENT.md)
|
||||||
git add .
|
- Git operations (commit, push, tag)
|
||||||
git commit -m "Description of changes"
|
|
||||||
git push
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Create Release** (when ready)
|
## Development Workflow
|
||||||
- Update version in `manifest.json`
|
|
||||||
- Push changes
|
|
||||||
- Create new GitHub release (e.g., v1.1.0)
|
|
||||||
- HACS will auto-detect and notify users
|
|
||||||
|
|
||||||
### Switching to HACS Version (Future)
|
### 1. Make Changes
|
||||||
|
|
||||||
When you want to use the HACS version instead of development:
|
```bash
|
||||||
|
cd /path/to/your/spotify-voice-assistant
|
||||||
|
# Edit files in custom_components/spotify_search/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Test Changes
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# For Python code changes - full restart
|
||||||
|
docker restart homeassistant
|
||||||
|
|
||||||
|
# For YAML changes - reload only (faster)
|
||||||
|
# Use Developer Tools > YAML > Core Configuration
|
||||||
|
|
||||||
|
# Watch logs in real-time
|
||||||
|
docker logs -f homeassistant 2>&1 | grep spotify_search
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Commit Changes
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "Description of changes"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Create Release (when ready)
|
||||||
|
|
||||||
|
- Update version in `manifest.json`
|
||||||
|
- Push changes
|
||||||
|
- Create new GitHub release (e.g., v1.1.0)
|
||||||
|
- HACS will auto-detect and notify users
|
||||||
|
|
||||||
|
## Switching Between Development and HACS
|
||||||
|
|
||||||
|
### Switch to HACS Version
|
||||||
|
|
||||||
|
When you want to use the stable HACS version instead of development:
|
||||||
|
|
||||||
|
**For bind mount setup:**
|
||||||
|
```bash
|
||||||
|
# Remove the bind mount from your Docker configuration
|
||||||
|
# Recreate the container without the bind mount
|
||||||
|
docker restart homeassistant
|
||||||
|
|
||||||
|
# Install via HACS
|
||||||
|
# HACS > Integrations > Spotify Voice Assistant > Install
|
||||||
|
# Restart Home Assistant
|
||||||
|
```
|
||||||
|
|
||||||
|
**For symlink setup:**
|
||||||
```bash
|
```bash
|
||||||
# Remove symlink
|
# Remove symlink
|
||||||
rm /path/to/homeassistant/config/custom_components/spotify_search
|
rm /path/to/homeassistant/config/custom_components/spotify_search
|
||||||
|
|
||||||
# Install via HACS
|
# Install via HACS
|
||||||
# HACS > Integrations > Spotify Voice Assistant > Install
|
# HACS > Integrations > Spotify Voice Assistant > Install
|
||||||
|
|
||||||
# Restart Home Assistant
|
# Restart Home Assistant
|
||||||
```
|
```
|
||||||
|
|
||||||
### Switching Back to Development
|
### Switch Back to Development
|
||||||
|
|
||||||
|
**For bind mount setup:**
|
||||||
|
```bash
|
||||||
|
# Add the bind mount back to your Docker configuration
|
||||||
|
# Recreate/restart the container
|
||||||
|
docker restart homeassistant
|
||||||
|
```
|
||||||
|
|
||||||
|
**For symlink setup:**
|
||||||
```bash
|
```bash
|
||||||
# Remove HACS version
|
# Remove HACS version
|
||||||
rm -rf /path/to/homeassistant/config/custom_components/spotify_search
|
rm -rf /path/to/homeassistant/config/custom_components/spotify_search
|
||||||
@@ -78,7 +148,6 @@ ln -s /path/to/your/spotify-voice-assistant/custom_components/spotify_search \
|
|||||||
/path/to/homeassistant/config/custom_components/spotify_search
|
/path/to/homeassistant/config/custom_components/spotify_search
|
||||||
|
|
||||||
# Restart Home Assistant
|
# Restart Home Assistant
|
||||||
# Method varies by installation type (Docker, Core, Supervised, etc.)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing Checklist
|
## Testing Checklist
|
||||||
@@ -89,9 +158,12 @@ Before each release:
|
|||||||
- [ ] Test artist search with first result fallback
|
- [ ] Test artist search with first result fallback
|
||||||
- [ ] Test album search
|
- [ ] Test album search
|
||||||
- [ ] Test track search
|
- [ ] Test track search
|
||||||
- [ ] Test via voice commands
|
- [ ] Test playlist search
|
||||||
- [ ] Test via Developer Tools
|
- [ ] Test via voice commands through Extended OpenAI Conversation
|
||||||
|
- [ ] Test via Developer Tools service call
|
||||||
|
- [ ] Test clear_cache service
|
||||||
- [ ] Check debug logs for errors
|
- [ ] Check debug logs for errors
|
||||||
|
- [ ] Verify caching is working (check debug logs for "Using cached Spotify client")
|
||||||
- [ ] Verify version in manifest.json is updated
|
- [ ] Verify version in manifest.json is updated
|
||||||
- [ ] Update README if features changed
|
- [ ] Update README if features changed
|
||||||
|
|
||||||
@@ -101,7 +173,7 @@ Before each release:
|
|||||||
spotify-voice-assistant/
|
spotify-voice-assistant/
|
||||||
├── custom_components/
|
├── custom_components/
|
||||||
│ └── spotify_search/
|
│ └── spotify_search/
|
||||||
│ ├── __init__.py # Main integration code
|
│ ├── __init__.py # Main integration code (186 lines)
|
||||||
│ ├── manifest.json # Version and metadata
|
│ ├── manifest.json # Version and metadata
|
||||||
│ └── services.yaml # Service definitions
|
│ └── services.yaml # Service definitions
|
||||||
├── examples/ # User examples
|
├── examples/ # User examples
|
||||||
@@ -124,20 +196,48 @@ logger:
|
|||||||
custom_components.spotify_search: debug
|
custom_components.spotify_search: debug
|
||||||
```
|
```
|
||||||
|
|
||||||
|
After adding debug logging, restart Home Assistant to apply.
|
||||||
|
|
||||||
### Common Debug Commands
|
### Common Debug Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Watch integration logs in real-time (Docker example)
|
# Watch integration logs in real-time (Docker example)
|
||||||
docker logs -f homeassistant 2>&1 | grep spotify_search
|
docker logs -f homeassistant 2>&1 | grep spotify_search
|
||||||
|
|
||||||
# Check if integration loaded
|
# Check if integration loaded successfully
|
||||||
# Look for "Setting up spotify_search" in Home Assistant logs
|
docker logs homeassistant 2>&1 | grep "Setting up spotify_search"
|
||||||
|
|
||||||
# Verify symlink (if using symlink development)
|
# Verify bind mount or symlink
|
||||||
|
# For bind mount:
|
||||||
|
docker inspect homeassistant | grep spotify_search
|
||||||
|
|
||||||
|
# For symlink:
|
||||||
ls -la /path/to/homeassistant/config/custom_components/spotify_search
|
ls -la /path/to/homeassistant/config/custom_components/spotify_search
|
||||||
|
|
||||||
# Check manifest version
|
# Check manifest version
|
||||||
cat custom_components/spotify_search/manifest.json | grep version
|
cat custom_components/spotify_search/manifest.json | grep version
|
||||||
|
|
||||||
|
# Check Python syntax without running
|
||||||
|
python3 -m py_compile custom_components/spotify_search/__init__.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug Logging Output
|
||||||
|
|
||||||
|
When working correctly, you should see:
|
||||||
|
```
|
||||||
|
INFO Setting up spotify_search
|
||||||
|
INFO Setup of domain spotify_search took 0.00 seconds
|
||||||
|
DEBUG Cache miss, performing Spotify entity lookup
|
||||||
|
DEBUG Found Spotify entity: media_player.spotify_xxx
|
||||||
|
DEBUG Spotify client type: SpotifyClient
|
||||||
|
INFO Cached Spotify client for entity: media_player.spotify_xxx
|
||||||
|
DEBUG Searching for artist: Coldplay
|
||||||
|
INFO Found Spotify artist: Coldplay (spotify:artist:4gzpq5DPGxSnKTe4SA8HAU) - exact match
|
||||||
|
```
|
||||||
|
|
||||||
|
Subsequent searches should show:
|
||||||
|
```
|
||||||
|
DEBUG Using cached Spotify client # <-- Caching is working!
|
||||||
```
|
```
|
||||||
|
|
||||||
### Test Service Call
|
### Test Service Call
|
||||||
@@ -159,24 +259,58 @@ Expected response:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Test Clear Cache Service
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
service: spotify_search.clear_cache
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Cache cleared"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Notes
|
||||||
|
|
||||||
|
The v1.0.0 release includes client caching that provides 15-50x performance improvement:
|
||||||
|
|
||||||
|
- **Without cache:** ~150-500ms per search (full entity lookup)
|
||||||
|
- **With cache:** ~3-10ms per search (cached client reuse)
|
||||||
|
|
||||||
|
Cache automatically invalidates if the Spotify integration is reloaded or removed.
|
||||||
|
|
||||||
## Version Numbering
|
## Version Numbering
|
||||||
|
|
||||||
Follow semantic versioning:
|
Follow semantic versioning:
|
||||||
- **v1.0.x** - Bug fixes only
|
- **v1.0.x** - Bug fixes only
|
||||||
- **v1.x.0** - New features (playlist support, config options, etc.)
|
- **v1.x.0** - New features (config options, additional search types, etc.)
|
||||||
- **v2.0.0** - Breaking changes (API changes, config changes, etc.)
|
- **v2.0.0** - Breaking changes (API changes, config changes, etc.)
|
||||||
|
|
||||||
## Contributing to Your Own Repo
|
## Release Process
|
||||||
|
|
||||||
When making improvements:
|
When making improvements:
|
||||||
|
|
||||||
1. Create a feature branch (optional for solo development)
|
1. Make changes and test thoroughly with checklist above
|
||||||
2. Make changes and test thoroughly
|
2. Update version in `manifest.json`
|
||||||
3. Update version in manifest.json
|
3. Commit with descriptive message (no AI attribution)
|
||||||
4. Commit with descriptive message
|
4. Push to main branch
|
||||||
5. Push to main branch
|
5. Create GitHub release with tag matching manifest version
|
||||||
6. Create GitHub release
|
6. HACS users will be notified automatically
|
||||||
7. HACS users will be notified automatically
|
|
||||||
|
**Example:**
|
||||||
|
```bash
|
||||||
|
# Update manifest.json version to 1.1.0
|
||||||
|
git add custom_components/spotify_search/manifest.json
|
||||||
|
git commit -m "Add support for podcast search"
|
||||||
|
git push
|
||||||
|
|
||||||
|
# Create release on GitHub
|
||||||
|
gh release create v1.1.0 --title "v1.1.0 - Podcast Search Support" \
|
||||||
|
--notes "Added support for searching Spotify podcasts"
|
||||||
|
```
|
||||||
|
|
||||||
## Backup Strategy
|
## Backup Strategy
|
||||||
|
|
||||||
@@ -191,3 +325,59 @@ tar -czf spotify-voice-assistant-backup-$(date +%Y%m%d).tar.gz \
|
|||||||
cp /path/to/homeassistant/config/configuration.yaml \
|
cp /path/to/homeassistant/config/configuration.yaml \
|
||||||
configuration-backup-$(date +%Y%m%d).yaml
|
configuration-backup-$(date +%Y%m%d).yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
### Integration Not Loading
|
||||||
|
|
||||||
|
**Symptom:** No "Setting up spotify_search" in logs
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
1. Verify bind mount or symlink is correct
|
||||||
|
2. Check `configuration.yaml` has `spotify_search:` entry
|
||||||
|
3. Ensure files are readable by HA container user
|
||||||
|
4. Look for Python syntax errors in logs
|
||||||
|
|
||||||
|
**Docker bind mount check:**
|
||||||
|
```bash
|
||||||
|
docker inspect homeassistant | grep -A2 spotify_search
|
||||||
|
```
|
||||||
|
|
||||||
|
### Symlink Not Working in Docker
|
||||||
|
|
||||||
|
**Symptom:** Integration loads but shows errors about missing files
|
||||||
|
|
||||||
|
**Solution:** Symlinks must point to paths accessible from inside the container. Use bind mounts instead (see setup section above).
|
||||||
|
|
||||||
|
### Changes Not Reflecting
|
||||||
|
|
||||||
|
**Symptom:** Made changes but HA still runs old code
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Ensure you're editing the correct files (check bind mount/symlink target)
|
||||||
|
2. Restart HA after Python code changes
|
||||||
|
3. Check for cached `.pyc` files in `__pycache__/` and clear if needed
|
||||||
|
4. Verify bind mount is not read-only when testing (remove `:ro` temporarily)
|
||||||
|
|
||||||
|
## Code Quality
|
||||||
|
|
||||||
|
### Before Committing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check Python syntax
|
||||||
|
python3 -m py_compile custom_components/spotify_search/__init__.py
|
||||||
|
|
||||||
|
# Check for common issues
|
||||||
|
grep -n "TODO\|FIXME\|XXX" custom_components/spotify_search/*.py
|
||||||
|
|
||||||
|
# Ensure no debug print statements
|
||||||
|
grep -n "print(" custom_components/spotify_search/*.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Standards
|
||||||
|
|
||||||
|
- Use lazy logging: `_LOGGER.debug("Text: %s", var)` not `_LOGGER.debug(f"Text: {var}")`
|
||||||
|
- Use defensive programming: check attributes with `hasattr()` before accessing
|
||||||
|
- Validate all user inputs
|
||||||
|
- Handle specific exceptions before generic ones
|
||||||
|
- Keep functions focused and under 50 lines when possible
|
||||||
|
|||||||
Reference in New Issue
Block a user