class I2CAddress:
    def __init__(self, device_class: int, device_address: int, channel_number: int = -1):
        if device_class > 15: # 4 Bit Maximum
            raise ValueError(f"Invalid I2C device class {device_class}")
        if device_address > 7: # 3 Bit Maximum
            raise ValueError(f"Invalid I2C device address {device_address}")
            
        self.device_class = device_class
        self.device_address = device_address
        self.channel_number = channel_number
        
        # Berechnung der Basis-Adresse (8-Bit Format mit R/W = 0)
        # Java: slaveAddress = deviceClass << 4 | deviceAddress << 1;
        self._slave_address = (device_class << 4) | (device_address << 1)

    @property
    def write_address(self) -> int:
        """Gibt die 8-bit Schreibadresse zurück (Bit 0 ist 0)."""
        return self._slave_address & 0xFE

    @property
    def read_address(self) -> int:
        """Gibt die 8-bit Leseadresse zurück (Bit 0 ist 1)."""
        return self._slave_address | 0x01

    @property
    def address_7bit(self) -> int:
        """Gibt die klassische 7-bit Adresse zurück."""
        return self._slave_address >> 1

    def __str__(self):
        chan = f"({self.channel_number})" if self.channel_number != -1 else ""
        return f"{self.device_class}/{self.device_address}{chan}"

    def __eq__(self, other):
        if not isinstance(other, I2CAddress):
            return False
        return (self.device_class == other.device_class and 
                self.device_address == other.device_address and 
                self.channel_number == other.channel_number)