Add Docker containerization and Raspberry Pi support
- Add Dockerfile with multi-architecture support (AMD64/ARM64/ARMv7) - Add docker-compose.yml with continuous and manual run options - Add comprehensive Docker documentation (README-DOCKER.md) - Add CLAUDE.md for future development guidance - Update README.md with Docker deployment and UniFi Protect future goals - Configure individual door device support (vs door groups) - Add Raspberry Pi compatibility and deployment instructions - Include memory limits for Pi optimization 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>main
parent
ec9f997c73
commit
e080aba000
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(cp:*)",
|
||||
"Bash(python3:*)",
|
||||
"Bash(pip install:*)",
|
||||
"Bash(mkdir:*)",
|
||||
"Bash(git add:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# Ignore log files
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Ignore git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Ignore Docker files
|
||||
Dockerfile
|
||||
docker-compose.yml
|
||||
.dockerignore
|
||||
|
||||
# Ignore Python cache
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
|
||||
# Ignore IDE files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Ignore OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a Python automation tool that integrates UniFi Access with Airbnb/Hostex reservations, automatically creating and managing visitor access for Airbnb guests. The system fetches reservations from either Hostex API or Airbnb ICS feed, creates UniFi Access visitor accounts with PIN codes based on phone numbers, and provides cross-verification between multiple booking systems.
|
||||
|
||||
## Core Commands
|
||||
|
||||
### Development and Execution
|
||||
- **Run the application**: `python3 main.py`
|
||||
- **Install dependencies**: `pip install -r requirements.txt`
|
||||
- **Run with verbose logging**: `python3 main.py -v`
|
||||
- **Specify custom log file**: `python3 main.py -l custom.log`
|
||||
- **List available door groups**: `python3 main.py --list-door-groups`
|
||||
|
||||
### Configuration Setup
|
||||
- **Setup configuration**: `cp unifi.conf.example unifi.conf` then edit with actual credentials
|
||||
- **Configuration file**: `unifi.conf` (contains API tokens, URLs, and settings)
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Core Components
|
||||
|
||||
1. **main.py** - Entry point and orchestration
|
||||
- Handles command-line arguments and logging setup
|
||||
- Coordinates all managers and performs cross-system verification
|
||||
- Implements `verify_across_systems()` for data consistency checks
|
||||
|
||||
2. **unifi_access.py** - UniFi Access API integration
|
||||
- `UnifiAccessManager` class handles all UniFi Access operations
|
||||
- Creates/deletes visitors, assigns PIN codes, manages door group access
|
||||
- Processes reservations and maintains visitor lifecycle
|
||||
|
||||
3. **hostex_api.py** - Hostex API integration
|
||||
- `HostexManager` fetches reservations from Hostex booking platform
|
||||
- Simple API wrapper for reservation data
|
||||
|
||||
4. **ics_parser.py** - Airbnb ICS calendar parsing
|
||||
- `ICSParser` processes Airbnb calendar feeds
|
||||
- Extracts reservation data and PIN codes from ICS events
|
||||
|
||||
5. **notification.py** - Simplepush notifications
|
||||
- `NotificationManager` sends status updates and alerts
|
||||
- Configurable notification system for operational updates
|
||||
|
||||
6. **config.py** - Configuration management
|
||||
- Centralizes configuration loading from `unifi.conf`
|
||||
- Handles API credentials, timing settings, and feature flags
|
||||
|
||||
7. **utils.py** - Shared utilities
|
||||
- Logging setup and configuration
|
||||
|
||||
### Data Flow Architecture
|
||||
|
||||
```
|
||||
Hostex API ──┐
|
||||
├──► Cross-Verification ──► UniFi Access API
|
||||
ICS Feed ────┘ (Visitor Management)
|
||||
│
|
||||
▼
|
||||
Simplepush Notifications
|
||||
```
|
||||
|
||||
### Key Integration Points
|
||||
|
||||
- **Reservation Sources**: Supports both Hostex API and Airbnb ICS feeds
|
||||
- **PIN Code Generation**: Uses last N digits of guest phone numbers
|
||||
- **Cross-Verification**: Matches reservations across systems to detect discrepancies
|
||||
- **Visitor Lifecycle**: Automatically creates visitors for upcoming stays, deletes past/completed visits
|
||||
- **Door Access**: Assigns visitors to configurable door groups in UniFi Access
|
||||
|
||||
## Configuration Structure
|
||||
|
||||
The `unifi.conf` file contains these key sections:
|
||||
- `[UniFi]`: Access controller API endpoint and authentication token
|
||||
- `[Hostex]`: Hostex API credentials (optional if using ICS only)
|
||||
- `[Airbnb]`: ICS calendar feed URL (optional if using Hostex only)
|
||||
- `[Door]`: Default door group ID for visitor access
|
||||
- `[Visitor]`: Check-in/out times and PIN code settings
|
||||
- `[Simplepush]`: Notification service configuration
|
||||
- `[General]`: Logging and PIN code digit count
|
||||
|
||||
## Development Notes
|
||||
|
||||
### Dependencies
|
||||
- `requests`: HTTP API calls to UniFi Access and Hostex
|
||||
- `icalendar`: Parsing Airbnb ICS calendar feeds
|
||||
- `urllib3`: HTTP utilities (with SSL warning suppression)
|
||||
- `configparser`: Configuration file parsing
|
||||
|
||||
### Logging Strategy
|
||||
- Comprehensive debug logging available with `-v` flag
|
||||
- File-based logging for operational history
|
||||
- Different log levels for console vs file output
|
||||
|
||||
### API Integrations
|
||||
- **UniFi Access**: RESTful API for visitor management, requires authentication token
|
||||
- **Hostex**: Booking platform API for reservation data
|
||||
- **Simplepush**: Simple HTTP-based notification service
|
||||
- **Airbnb ICS**: Calendar feed parsing for reservation extraction
|
||||
|
||||
### Testing and Verification
|
||||
- Use `--list-door-groups` to verify UniFi Access connectivity and available door groups
|
||||
- Run with `-v` flag to see detailed operation logs
|
||||
- Check log files for historical operation data and error analysis
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Use Python 3.11 slim image (supports amd64, arm64, arm/v7)
|
||||
FROM python:3.11-slim
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy requirements and install dependencies
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy application code
|
||||
COPY *.py ./
|
||||
COPY unifi.conf ./
|
||||
|
||||
# Create logs directory
|
||||
RUN mkdir -p /app/logs
|
||||
|
||||
# Set environment variables
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Default command (can be overridden)
|
||||
CMD ["python", "main.py"]
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
# Docker Setup for UniFi Access Airbnb Integration
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Build and run continuously** (checks every 6 hours):
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
2. **Run once manually**:
|
||||
```bash
|
||||
docker-compose --profile manual up unifi-access-airbnb-once
|
||||
```
|
||||
|
||||
3. **View logs**:
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
# Or check the logs directory: ./logs/unifi_access_airbnb.log
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
- **Config file**: Edit `unifi.conf` on the host - it's mounted read-only into the container
|
||||
- **Logs**: Persistent in `./logs/` directory
|
||||
- **Timezone**: Set in docker-compose.yml (default: America/New_York)
|
||||
|
||||
## Automation Options
|
||||
|
||||
### Option 1: Continuous Container (Recommended)
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
Runs every 6 hours automatically. Change interval by modifying `sleep 21600` in docker-compose.yml.
|
||||
|
||||
### Option 2: Cron Job + Manual Container
|
||||
```bash
|
||||
# Add to crontab to run daily at 8 AM:
|
||||
0 8 * * * cd /path/to/project && docker-compose --profile manual up unifi-access-airbnb-once
|
||||
```
|
||||
|
||||
### Option 3: Windows Task Scheduler
|
||||
Create a scheduled task that runs:
|
||||
```cmd
|
||||
docker-compose --profile manual up unifi-access-airbnb-once
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
- **Stop**: `docker-compose down`
|
||||
- **Rebuild**: `docker-compose build`
|
||||
- **View container status**: `docker-compose ps`
|
||||
- **Interactive shell**: `docker-compose exec unifi-access-airbnb sh`
|
||||
|
||||
## Raspberry Pi Deployment
|
||||
|
||||
### Compatibility
|
||||
✅ **Raspberry Pi 4/5** (ARM64) - Full support
|
||||
✅ **Raspberry Pi 3B+** (ARM32/ARMv7) - Full support
|
||||
✅ **Raspberry Pi Zero 2 W** (ARM64) - Works but slower
|
||||
|
||||
### Pi-Specific Setup
|
||||
```bash
|
||||
# 1. Install Docker (if not already installed)
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
sudo usermod -aG docker pi
|
||||
|
||||
# 2. Install docker-compose
|
||||
sudo apt update
|
||||
sudo apt install docker-compose-plugin
|
||||
|
||||
# 3. Clone and run your project
|
||||
git clone <your-repo>
|
||||
cd unifi-access-airbnb
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Performance Notes
|
||||
- **Pi 4/5**: Excellent performance, recommended for production
|
||||
- **Pi 3B+**: Good performance, slightly slower container startup
|
||||
- **Pi Zero 2**: Functional but slower, consider running less frequently
|
||||
|
||||
### Power Management
|
||||
For reliable operation on Pi:
|
||||
```yaml
|
||||
# Add to docker-compose.yml services section:
|
||||
restart: always
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 128M
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Check logs**: `docker-compose logs unifi-access-airbnb`
|
||||
- **Test config**: `docker-compose --profile manual up unifi-access-airbnb-once`
|
||||
- **Network issues**: Ensure container can reach UniFi controller IP (10.0.1.20)
|
||||
- **Pi-specific**: Check `docker --version` and ensure Docker is running: `sudo systemctl status docker`
|
||||
58
README.md
58
README.md
|
|
@ -84,6 +84,62 @@ The script performs several verification checks:
|
|||
- Reports discrepancies in dates or guest information
|
||||
- Monitors UniFi Access visitor status
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
For easy deployment and automation, this project includes Docker support:
|
||||
|
||||
### Quick Start with Docker
|
||||
```bash
|
||||
# Build and run continuously (checks every 6 hours)
|
||||
docker-compose up -d
|
||||
|
||||
# Run once manually
|
||||
docker-compose --profile manual up unifi-access-airbnb-once
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
See [README-DOCKER.md](README-DOCKER.md) for complete Docker setup instructions.
|
||||
|
||||
### Raspberry Pi Support
|
||||
The Docker container runs perfectly on Raspberry Pi (ARM64/ARM32). Simply:
|
||||
```bash
|
||||
# On Raspberry Pi
|
||||
docker-compose up -d
|
||||
```
|
||||
Docker automatically pulls the correct architecture. See [README-DOCKER.md](README-DOCKER.md) for Pi-specific notes.
|
||||
|
||||
## Future Goals
|
||||
|
||||
### UniFi Protect Integration
|
||||
Plans to extend this project with UniFi Protect video recording capabilities:
|
||||
|
||||
**Required Hardware:**
|
||||
- UniFi Gateway Max (UDM-Pro Max) with built-in NVR
|
||||
- OR UniFi Cloud Key Gen2+ with Protect
|
||||
|
||||
**Planned Features:**
|
||||
- **Guest Check-in Recording**: Automatically start recording when guests arrive
|
||||
- **Stay Duration Recording**: Record during entire guest stay period
|
||||
- **Checkout Verification**: Capture departure recordings
|
||||
- **Incident Documentation**: Archive recordings for property protection
|
||||
- **Guest Privacy**: Automatic recording pause/resume based on occupancy
|
||||
|
||||
**Implementation Ideas:**
|
||||
- Integrate with UniFi Protect API for camera control
|
||||
- Coordinate recording schedules with visitor access periods
|
||||
- Provide guest notification of recording periods (legal compliance)
|
||||
- Archive system for easy retrieval of guest-specific recordings
|
||||
|
||||
**Benefits:**
|
||||
- Property protection during guest stays
|
||||
- Incident documentation and liability protection
|
||||
- Automated recording management tied to booking system
|
||||
- Enhanced security without manual camera management
|
||||
|
||||
This would create a complete property automation ecosystem: **Access Control + Video Security** synchronized with your Airbnb bookings.
|
||||
|
||||
## Contributing
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
|
|
@ -94,4 +150,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|||
If you encounter any issues or have questions:
|
||||
1. Check the logs using verbose mode
|
||||
2. Review your configuration file
|
||||
3. Open an issue on GitHub with relevant logs and details```
|
||||
3. Open an issue on GitHub with relevant logs and details
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
unifi-access-airbnb:
|
||||
build: .
|
||||
container_name: unifi-access-airbnb
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
# Mount config file (edit this on host)
|
||||
- ./unifi.conf:/app/unifi.conf:ro
|
||||
# Mount logs directory for persistence
|
||||
- ./logs:/app/logs
|
||||
environment:
|
||||
- TZ=America/New_York # Set your timezone
|
||||
# Resource limits for Raspberry Pi compatibility
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 128M
|
||||
reservations:
|
||||
memory: 64M
|
||||
# Run every 6 hours by default
|
||||
command: sh -c "while true; do python main.py; sleep 21600; done"
|
||||
|
||||
# Alternative: Run once and exit (for cron-like usage)
|
||||
unifi-access-airbnb-once:
|
||||
build: .
|
||||
container_name: unifi-access-airbnb-once
|
||||
profiles:
|
||||
- manual # Only start with: docker-compose --profile manual up
|
||||
volumes:
|
||||
- ./unifi.conf:/app/unifi.conf:ro
|
||||
- ./logs:/app/logs
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
command: python main.py -v
|
||||
|
|
@ -16,10 +16,10 @@ class UnifiAccessManager:
|
|||
|
||||
self.logger.debug(f"Loaded default_door_group_id from config: {self.default_door_group_id}")
|
||||
if not self.default_door_group_id:
|
||||
self.logger.warning("default_door_group_id is not set in config. Attempting to fetch available door groups.")
|
||||
self.set_default_door_group()
|
||||
self.logger.error("default_group_id is not set in config. Please set it to your door device ID.")
|
||||
raise ValueError("default_group_id is required in config")
|
||||
else:
|
||||
self.logger.debug(f"Initialized with default_door_group_id: {self.default_door_group_id}")
|
||||
self.logger.debug(f"Initialized with door device ID: {self.default_door_group_id}")
|
||||
|
||||
def set_default_door_group(self):
|
||||
door_groups = self.fetch_door_groups()
|
||||
|
|
@ -50,7 +50,7 @@ class UnifiAccessManager:
|
|||
"resources": [
|
||||
{
|
||||
"id": self.default_door_group_id,
|
||||
"type": "door_group"
|
||||
"type": "door"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -233,6 +233,7 @@ class UnifiAccessManager:
|
|||
return bool(self.changes['added'] or self.changes['deleted'])
|
||||
|
||||
def fetch_door_groups(self):
|
||||
# Try door_groups first, then user_groups if empty
|
||||
url = f"{self.api_host}/api/v1/developer/door_groups"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {self.api_token}",
|
||||
|
|
@ -240,6 +241,7 @@ class UnifiAccessManager:
|
|||
}
|
||||
response = requests.get(url, headers=headers, verify=False)
|
||||
self.logger.debug(f"Fetch door groups API response status code: {response.status_code}")
|
||||
self.logger.debug(f"Fetch door groups API response content: {response.text}")
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
|
|
|
|||
Loading…
Reference in New Issue