Hermanas is a comprehensive chicken coop automation system designed to run on Raspberry Pi hardware. It automates door operations based on sunrise/sunset times, manages environmental controls (lighting, ventilation, music), monitors temperature and humidity, and provides real-time camera surveillance.
Live Demo: http://www.hermanas.fr Frontend Repository: https://github.com/jibe77/hermanasclient
- Intelligent Door Control - Automatic door opening/closing based on sunrise/sunset calculations with customizable delays
- Sun-Based Scheduling - Location-aware scheduling using real-time astronomical calculations
- Event Sourcing - Complete audit trail of all door operations for troubleshooting and analytics
- Temperature & Humidity Monitoring - Real-time sensor data with historical tracking
- Automated Ventilation - Fan control with energy-conscious timer management
- Smart Lighting - Scheduled lighting with eco/regular/sunny mode support
- Music Playback - Audio stimulation for chickens with timer control
- Live Camera Streaming - Real-time video surveillance with image capture
- AI-Powered Door Detection - Automatic detection of door closing issues using computer vision
- WebSocket Real-Time Updates - Live status notifications via STOMP protocol
- Health Monitoring - Spring Boot Actuator health checks for all components
- Three Power Modes - Eco (winter), Regular, and Sunny (summer) consumption profiles
- Configurable Timers - Mode-specific timer delays for all equipment
- WiFi Power Control - Automatic WiFi disable in eco mode
- Machine Shutdown - Scheduled system shutdown capabilities in low-power modes
- REST API - Complete
/api/v1/*endpoints for all operations - Swagger Documentation - Interactive API documentation
- Siri Integration - Control via iOS shortcuts and voice commands
- Security - Spring Security with role-based access control
- Raspberry Pi Zero (or any Raspberry Pi model with GPIO)
- Servo Motor - Door mechanism (GPIO 25)
- Limit Switches - Top (GPIO 15) and bottom (GPIO 18) door position sensors
- DHT11/DHT22 Sensor - Temperature and humidity (GPIO 4)
- Relay Modules - Light (GPIO 14), Fan (GPIO 23), Music control
- Pi Camera Module - Video surveillance
- MariaDB Server - Database (can run on separate machine)
- External Storage - For camera image archives
- UPS/Battery - Power backup for safe shutdowns
# Java 11 (required for Pi Zero compatibility)
java -version # Should show 1.11.x
# Maven 3.6+
mvn -version
# MariaDB 10.x
mysql --version-
Clone the repository
git clone https://github.com/jibe77/hermanas.git cd hermanas -
Configure the application
cp src/main/resources/application.properties.example src/main/resources/application.properties # Edit application.properties with your settings (see Configuration section) -
Build the application
mvn clean package
-
Run the application
# On Raspberry Pi with real GPIO hardware java -jar target/hermanas-0.8.jar # On development machine with fake GPIO mvn spring-boot:run -Dspring.profiles.active=gpio-fake
-
Access the application
- API:
http://localhost:8080/api/v1/ - Swagger UI:
http://localhost:8080/swagger-ui/index.html - Health:
http://localhost:8080/actuator/health - Metrics:
http://localhost:8080/actuator/metrics
- API:
Key configuration parameters in application.properties:
spring.datasource.url=jdbc:mariadb://localhost:3306/hermanas
spring.datasource.username=hermanas
spring.datasource.password=your_password# Door control
gpio.pin.servo=25
gpio.pin.servo.button.up=15
gpio.pin.servo.button.bottom=18
# Environmental controls
gpio.pin.light=14
gpio.pin.fan=23
gpio.pin.sensor=4# Servo motor timing (milliseconds)
servo.pin.opening.duration=10000
servo.pin.closing.duration=2350
servo.door.closing.position=5
servo.door.opening.position=16# Coordinates for sunrise/sunset calculations
location.latitude=48.8566
location.longitude=2.3522# Minutes after sunrise to open door
scheduler.sun.door.opening.delay=10
# Minutes before sunset to close door
scheduler.sun.door.closing.delay=30# Eco mode (winter solstice)
consumption.mode.eco.days.around.winter.solstice=30
consumption.mode.eco.light.timer.delay=300000
consumption.mode.eco.fan.timer.delay=300000
consumption.mode.eco.music.timer.delay=300000
consumption.mode.eco.machine.shutdown=true
consumption.mode.eco.wifi.disabled=true
# Sunny mode (summer solstice)
consumption.mode.sunny.days.around.summer.solstice=30
consumption.mode.sunny.light.timer.delay=900000
consumption.mode.sunny.fan.timer.delay=900000
consumption.mode.sunny.music.timer.delay=900000camera.resolution.width=1024
camera.resolution.height=768
camera.jpeg.quality=85
camera.rotation=180
camera.streaming.port=8081Configuration values are cached for performance. To reload without restarting:
curl -X POST http://localhost:8080/api/v1/config/refreshAuthentication is self-hosted, file-based. There is no external identity provider.
Users live in a users.properties file outside the JAR (so rebuilds don't overwrite it).
The path is configurable via hermanas.security.users-file in application.properties
(default: ./users.properties, i.e. next to the JAR).
🔒 Never commit this file. It is already listed in
.gitignore.
# users.properties
# Each user has a .password (bcrypt hash, with the {bcrypt} prefix) and an optional .roles entry.
# Default role if .roles is omitted: USER
alice.password = {bcrypt}$2a$10$abcdefghijklmnopqrstuvABCDEFGHIJKLMNOPQRSTUVWXYZ012345
alice.roles = USER
bob.password = {bcrypt}$2a$10$zyxwvutsrqponmlkjihgfeZYXWVUTSRQPONMLKJIHGFEDCBA9876
bob.roles = USERThe JAR ships with a CLI to generate hashes — no external tools needed:
# Interactive (password not shown in shell history)
java -jar target/hermanas-0.8.jar --hash
# Password: ********
# {bcrypt}$2a$10$....
# Inline (avoid in shared terminals — leaves the password in history)
java -jar target/hermanas-0.8.jar --hash "your-password"Copy the {bcrypt}... line as-is into users.properties as the user's .password value.
# 1. Generate the hash
java -jar target/hermanas-0.8.jar --hash
# 2. Append to users.properties (next to the JAR, or wherever hermanas.security.users-file points)
echo "alice.password = {bcrypt}\$2a\$10\$..." >> users.properties
echo "alice.roles = USER" >> users.properties
# 3. Restart the application (the file is read at startup)
sudo systemctl restart hermanas- Login:
POST /api/v1/auth/loginwith form fieldsusername+password→ returns 200 on success (sets aJSESSIONIDcookie), 401 on failure - Current session:
GET /api/v1/auth/me→{ authenticated: false }when anonymous,{ authenticated: true, username, roles }otherwise - Logout:
POST /api/v1/auth/logout→ 204
CSRF is enabled: mutating requests must echo the XSRF-TOKEN cookie in the X-XSRF-TOKEN
header. Angular's HttpClient does this automatically.
# Open door
POST /api/v1/door/open?force=false
# Close door
POST /api/v1/door/close?force=false
# Get door status
GET /api/v1/door/status
# Get door event history
GET /api/v1/door/events
# Manual servo control (testing)
GET /api/v1/door/turnClockwise?duration=50
GET /api/v1/door/turnCounterClockwise?duration=50# Take picture
POST /api/v1/camera/takePicture
# Get door closing rate (AI analysis)
GET /api/v1/camera/closingRate
# Start/stop video stream
POST /api/v1/camera/stream
POST /api/v1/camera/stopStream# Get current sensor reading
GET /api/v1/sensor/info
# Get historical data
GET /api/v1/sensor/history/day
GET /api/v1/sensor/history/week
GET /api/v1/sensor/history/month
GET /api/v1/sensor/history/year
GET /api/v1/sensor/history/all# Light
POST /api/v1/light/switch
GET /api/v1/light/status
# Fan
POST /api/v1/fan/switch
GET /api/v1/fan/status
# Music
POST /api/v1/music/switch
GET /api/v1/music/status
POST /api/v1/music/cocorico # Play rooster sound# Get next scheduled events
GET /api/v1/scheduler/nextEvents
# Get specific times
GET /api/v1/scheduler/doorOpeningTime
GET /api/v1/scheduler/doorClosingTime
GET /api/v1/scheduler/lightOnTime# Get current consumption mode
GET /api/v1/energy/currentMode
GET /api/v1/energy/currentConfigMode
# WiFi control
GET /api/v1/energy/wifi/status
POST /api/v1/energy/wifi/enable
POST /api/v1/energy/wifi/disable
# Historical energy data
GET /api/v1/energy/dateRange?startDate=2024-01-01&endDate=2024-01-31# View current configuration
GET /api/v1/config
# Refresh caches (hot-reload)
POST /api/v1/config/refresh
# Update light timers
PUT /api/v1/config/light/eco?delayMs=300000
PUT /api/v1/config/light/regular?delayMs=600000
PUT /api/v1/config/light/sunny?delayMs=900000
# Update consumption mode
PUT /api/v1/config/consumption/eco-days?days=45
PUT /api/v1/config/consumption/force-eco?force=true
# Update system behavior
PUT /api/v1/config/system/eco/shutdown?enabled=false
PUT /api/v1/config/system/eco/wifi?disabled=true# System information
GET /api/v1/info
# Power management
POST /api/v1/system/shutdown
POST /api/v1/system/rebootInteractive API documentation with request/response examples:
http://localhost:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config
- Framework: Spring Boot 2.7.18 (Java 11)
- Database: MariaDB (production), H2 (testing)
- Hardware Interface: Pi4J 2.4.0
- Security: Spring Security with role-based access
- API Documentation: SpringDoc OpenAPI 1.8.0
- Scheduling: Quartz Scheduler
- Caching: Spring Cache
- Real-Time: WebSocket with STOMP
- Monitoring: Spring Boot Actuator + Micrometer
- Testing: JUnit 5, MockMvc, Spring Security Test
┌─────────────────────────────────────────┐
│ REST Controllers (/web package) │ ← HTTP endpoints
│ *RestController classes │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ Services (/controller package) │ ← Business logic & hardware abstraction
│ *Service classes │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ Repositories (/data/repository) │ ← Database access
│ Spring Data JPA interfaces │
└─────────────────────────────────────────┘
GpioHermanasService (interface)
├── GpioHermanasRpiService - Real Pi4j hardware (default)
└── GpioHermanasFakeService - Mock for testing (@Profile("gpio-fake"))
| Component | Purpose | Location |
|---|---|---|
| REST Controllers | HTTP API endpoints | org.jibe77.hermanas.web.*RestController |
| Services | Business logic & hardware control | org.jibe77.hermanas.controller.*Service |
| Schedulers | Automated jobs (sun, camera, disk) | org.jibe77.hermanas.scheduler.* |
| Event Sourcing | Door operation audit trail | org.jibe77.hermanas.controller.event.* |
| Health Indicators | Component health checks | org.jibe77.hermanas.health.* |
| Metrics | Micrometer metrics collection | org.jibe77.hermanas.metrics.* |
| WebSocket | Real-time notifications | org.jibe77.hermanas.websocket.* |
| Security | Authentication & authorization | org.jibe77.hermanas.security.* |
- SunRelatedJob - Every 60 seconds (door/light scheduling based on sun position)
- CameraJob - Every 3 hours (automated photo capture)
- DiskSpaceJob - Daily (storage monitoring)
-
Install dependencies
# macOS brew install maven openjdk@11 mariadb # Ubuntu/Debian apt-get install maven openjdk-11-jdk mariadb-server
-
Setup database
mysql -u root -p CREATE DATABASE hermanas; CREATE USER 'hermanas'@'localhost' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON hermanas.* TO 'hermanas'@'localhost'; FLUSH PRIVILEGES;
-
Use fake GPIO profile
mvn spring-boot:run -Dspring.profiles.active=gpio-fake
This allows development on non-Raspberry Pi hardware.
hermanas/
├── src/main/java/org/jibe77/hermanas/
│ ├── web/ # REST controllers (*RestController)
│ ├── controller/ # Services (*Service)
│ ├── data/ # Entities, repositories, DTOs
│ ├── scheduler/ # Quartz jobs & sun calculations
│ ├── security/ # Authentication & authorization
│ ├── health/ # Health indicators
│ ├── metrics/ # Micrometer metrics
│ ├── websocket/ # WebSocket configuration
│ └── HermanasApplication.java
├── src/main/resources/
│ ├── application.properties # Main configuration
│ └── static/ # Static web resources
├── src/test/java/ # Test suite
├── pom.xml # Maven dependencies
├── CLAUDE.md # AI assistant instructions
└── README.md # This file
# Clean and build
mvn clean package
# Run tests (excludes image processing tests)
mvn test
# Run all tests including image processing
mvn test -DexcludedGroups=
# Check for dependency updates
mvn versions:display-dependency-updates
# Check for plugin updates
mvn versions:display-plugin-updates
# Generate code coverage report
mvn test jacoco:report
# Report: target/site/jacoco/index.htmlThe project includes multiple test types:
- Unit Tests - Service layer testing with mocked dependencies
- REST Layer Tests -
@WebMvcTestwith MockMvc - Integration Tests -
@SpringBootTestfor end-to-end testing - Repository Tests -
@DataJpaTestfor database operations
Run tests without Raspberry Pi hardware:
mvn test -Dspring.profiles.active=gpio-fakeImage processing tests are tagged and excluded by default:
# Run only image processing tests
mvn test -Dgroups=image_processing- Logger Pattern: All classes use
private static final Logger logger = LoggerFactory.getLogger(ClassName.class) - Exception Handling: Global exception handler with
@ControllerAdvice - Input Validation:
@Valid,@Min,@Maxon request parameters - API Documentation: OpenAPI annotations on all endpoints
- DTOs: Separate DTOs from JPA entities for API responses
- Security: Audit logging with
@AuditLogannotation
-
Install Java 11
sudo apt-get update sudo apt-get install openjdk-11-jdk
-
Install MariaDB
sudo apt-get install mariadb-server sudo mysql_secure_installation
-
Install Pi4J native libraries
# Copy picam native library sudo cp native/picam-2.0.1.so /home/pi/ -
Configure GPIO permissions
sudo usermod -a -G gpio pi sudo usermod -a -G video pi
-
Deploy application
scp target/hermanas-0.8.jar pi@raspberrypi:/home/pi/
-
Create systemd service
sudo nano /etc/systemd/system/hermanas.service
[Unit] Description=Hermanas Chicken Coop Automation After=mariadb.service [Service] Type=simple User=pi ExecStart=/usr/bin/java -jar /home/pi/hermanas-0.8.jar SuccessExitStatus=143 Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target
-
Enable and start service
sudo systemctl daemon-reload sudo systemctl enable hermanas sudo systemctl start hermanas -
View logs
sudo journalctl -u hermanas -f
For production, externalize sensitive configuration:
# Create external config
sudo nano /etc/hermanas/application.properties
# Run with external config
java -jar hermanas-0.8.jar --spring.config.location=/etc/hermanas/application.properties# Overall health
curl http://localhost:8080/actuator/health
# Component-specific health
curl http://localhost:8080/actuator/health/door
curl http://localhost:8080/actuator/health/sensor# Available metrics
curl http://localhost:8080/actuator/metrics
# Door operations
curl http://localhost:8080/actuator/metrics/hermanas.door.operations
# Temperature gauge
curl http://localhost:8080/actuator/metrics/hermanas.sensor.temperature
# Door operation duration
curl http://localhost:8080/actuator/metrics/hermanas.door.operation.duration# View all door events
curl http://localhost:8080/api/v1/door/events
# Events include: DOOR_OPENED, DOOR_CLOSED, DOOR_OPEN_FAILED,
# DOOR_CLOSE_FAILED, DOOR_POSITION_UNKNOWNHermanas REST API can be called from any iOS device using Siri Shortcuts:
- Open Shortcuts app on iOS
- Create a new shortcut
- Add Get Contents of URL action
- Configure:
- URL:
http://your-pi-address:8080/api/v1/door/open - Method: POST
- Headers: Add Authorization header if needed
- URL:
- Name the shortcut: "Open chicken door"
- Say: "Hey Siri, open chicken door"
Example shortcuts:
- "Open chicken door" →
POST /api/v1/door/open - "Close chicken door" →
POST /api/v1/door/close - "Check coop temperature" →
GET /api/v1/sensor/info - "Turn on coop light" →
POST /api/v1/light/switch
# Check door health
curl http://localhost:8080/actuator/health/door
# View door event history
curl http://localhost:8080/api/v1/door/events
# Check door status
curl http://localhost:8080/api/v1/door/status
# Manual servo test (small movements)
curl "http://localhost:8080/api/v1/door/turnClockwise?duration=50"# Verify picam native library is loaded
ls -la /home/pi/picam-2.0.1.so
# Check camera permissions
groups pi | grep video
# Test camera
curl -X POST http://localhost:8080/api/v1/camera/takePicture# Check sensor health
curl http://localhost:8080/actuator/health/sensor
# Get current reading
curl http://localhost:8080/api/v1/sensor/info
# Verify GPIO pin configuration
cat /boot/config.txt | grep gpio# Check database connection
mysql -u hermanas -p hermanas
# View application logs
sudo journalctl -u hermanas -n 100
# Check database health
curl http://localhost:8080/actuator/health/dbThis application is designed for Raspberry Pi Zero, which imposes the following limitations:
- Java 11 Maximum - Cannot upgrade to Java 17+ due to hardware constraints
- Spring Boot 2.x - Cannot upgrade to Spring Boot 3.x (requires Java 17+)
- Pi4J 2.4.0 Maximum - Newer versions incompatible with Pi Zero + Java 11
- Picam 2.0.2 Maximum - Newer versions incompatible with Pi Zero + Java 11
These constraints are documented in CLAUDE.md. Upgrading to a more powerful Raspberry Pi model would remove these limitations.
Contributions are welcome! Please read CLAUDE.md for development guidelines and architecture decisions.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes with tests
- Ensure all tests pass (
mvn test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License.
- Issues: GitHub Issues
- Live Demo: http://www.hermanas.fr
- Frontend: https://github.com/jibe77/hermanasclient
- Spring Boot - Application framework
- Pi4J - Raspberry Pi GPIO library
- SunriseSunset Library - Astronomical calculations by Carmen
- Picam - Raspberry Pi camera interface
Built with care for our feathered friends.