Custom Adapter Example

This example demonstrates how to create custom device adapters for SmartHomeHarmonizer.

Note

This documentation is under development. See the example file for the current implementation.

Example Code

Custom coffee maker adapter
"""Example of creating a custom device adapter."""

from typing import Dict, Any, List, Optional
from smarthomeharmonizer.adapters.base import DeviceAdapter
from smarthomeharmonizer.core.exceptions import InvalidCommandError, AdapterError
import logging
import random

logger = logging.getLogger(__name__)


class SmartCoffeeMakerAdapter(DeviceAdapter):
    """Adapter for a smart coffee maker device."""
    
    SUPPORTED_COMMANDS = [
        'turnOn', 'turnOff', 'brew', 'setStrength', 
        'setSize', 'getStatus', 'clean'
    ]
    
    BREW_STRENGTHS = ['light', 'medium', 'strong', 'extra_strong']
    BREW_SIZES = ['small', 'medium', 'large']
    
    def _initialize_state(self) -> Dict[str, Any]:
        """Initialize coffee maker state."""
        return {
            'powerState': 'OFF',
            'brewing': False,
            'brewStrength': 'medium',
            'brewSize': 'medium',
            'waterLevel': 100,  # Percentage
            'coffeeBeans': 100,  # Percentage
            'needsCleaning': False,
            'lastBrewTime': None
        }
    
    def get_supported_commands(self) -> List[str]:
        """Get supported commands for coffee maker."""
        return self.SUPPORTED_COMMANDS
    
    def execute_command(self, command: str, parameters: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """Execute command on coffee maker."""
        if not self.validate_command(command):
            raise InvalidCommandError(f"Command '{command}' not supported by coffee maker")
        
        parameters = parameters or {}
        
        try:
            if command == 'turnOn':
                self._state['powerState'] = 'ON'
                logger.info(f"Coffee maker {self.device_id} turned ON")
                
            elif command == 'turnOff':
                self._state['powerState'] = 'OFF'
                self._state['brewing'] = False
                logger.info(f"Coffee maker {self.device_id} turned OFF")
                
            elif command == 'brew':
                if self._state['powerState'] == 'OFF':
                    raise ValueError("Coffee maker must be turned on first")
                if self._state['waterLevel'] < 20:
                    raise ValueError("Water level too low")
                if self._state['coffeeBeans'] < 10:
                    raise ValueError("Not enough coffee beans")
                if self._state['brewing']:
                    raise ValueError("Already brewing")
                
                self._state['brewing'] = True
                # Simulate resource consumption
                self._state['waterLevel'] -= 20
                self._state['coffeeBeans'] -= 10
                
                # Simulate cleaning need
                if random.random() > 0.7:
                    self._state['needsCleaning'] = True
                
                logger.info(f"Coffee maker {self.device_id} started brewing")
                
            elif command == 'setStrength':
                strength = parameters.get('strength')
                if strength not in self.BREW_STRENGTHS:
                    raise ValueError(f"Invalid strength. Must be one of: {self.BREW_STRENGTHS}")
                self._state['brewStrength'] = strength
                logger.info(f"Coffee maker {self.device_id} strength set to {strength}")
                
            elif command == 'setSize':
                size = parameters.get('size')
                if size not in self.BREW_SIZES:
                    raise ValueError(f"Invalid size. Must be one of: {self.BREW_SIZES}")
                self._state['brewSize'] = size
                logger.info(f"Coffee maker {self.device_id} size set to {size}")
                
            elif command == 'clean':
                self._state['needsCleaning'] = False
                logger.info(f"Coffee maker {self.device_id} cleaned")
                
            elif command == 'getStatus':
                # No state change, just return current state
                pass
                
        except Exception as e:
            logger.error(f"Error executing {command} on {self.device_id}: {str(e)}")
            raise AdapterError(f"Failed to execute {command}: {str(e)}")
        
        return self.get_state()


# Example usage
if __name__ == '__main__':
    from smarthomeharmonizer import create_app, DeviceManager
    
    # Create device manager
    manager = DeviceManager()
    
    # Register coffee maker
    coffee_maker = SmartCoffeeMakerAdapter('coffee1', 'Kitchen Coffee Maker')
    manager.register_device(coffee_maker)
    
    # Create and run app
    app = create_app(manager)
    
    print("Smart Coffee Maker registered!")
    print("Try these commands:")
    print("  POST /api/v1/devices/coffee1/command")
    print("    {'command': 'turnOn'}")
    print("    {'command': 'setStrength', 'parameters': {'strength': 'strong'}}")
    print("    {'command': 'brew'}")
    
    app.run(host='0.0.0.0', port=5000, debug=True)

For more information, see the example file in the repository.