import logging import time import cc1101 _ADDRESS_LENGTH_BITS = 26 _COMMAND_LENGTH_BITS = 2 _BUTTON_INDEX_LENGTH_BITS = 4 _MESSAGE_LENGTH_BITS = ( _ADDRESS_LENGTH_BITS + _COMMAND_LENGTH_BITS + _BUTTON_INDEX_LENGTH_BITS ) # > [...] default PATABLE setting (0xC6). # "24 Output Power Programming" in CC1101's docs DEFAULT_POWER_SETTING = 0xC6 _LOGGER = logging.getLogger(__name__) def _cc1101_transmit(payload: bytes, power_setting: int, repeats: int = 3) -> None: with cc1101.CC1101(lock_spi_device=True) as transceiver: transceiver.set_base_frequency_hertz(433.93e6) transceiver.set_symbol_rate_baud(3942) transceiver.set_sync_mode(cc1101.SyncMode.NO_PREAMBLE_AND_SYNC_WORD) transceiver.set_packet_length_mode(cc1101.PacketLengthMode.FIXED) transceiver.set_packet_length_bytes(len(payload)) transceiver.disable_checksum() transceiver.set_output_power((0, power_setting)) # OOK _LOGGER.info("%s", transceiver) for _ in range(repeats): transceiver.transmit(payload) time.sleep(0.08) def _encode_message(message: int) -> bytes: signal = [0b00000100, 0] assert 0 <= message < 2 ** _MESSAGE_LENGTH_BITS, message for bit_index in reversed(range(_MESSAGE_LENGTH_BITS)): if message & (0b1 << bit_index): signal.append(0b10000010) else: signal.append(0b10100000) signal.append(0b10000000) return bytes(signal) class RemoteControl: def __init__(self, address: int) -> None: if not isinstance(address, int): raise ValueError( "expected {}-bit unsigned integer as address, got {!r}".format( _ADDRESS_LENGTH_BITS, address ) ) if address < 0: raise ValueError("address must not be negative (got {!r})".format(address)) if address >= 2 ** _ADDRESS_LENGTH_BITS: raise ValueError( "address must not exceed {} ({}-bit unsigned integer), got {!r}".format( 2 ** _ADDRESS_LENGTH_BITS, _ADDRESS_LENGTH_BITS, address ) ) self._address = address def _send_command( self, command: int, button_index: int, power_setting: int ) -> None: assert 0 <= command < 2 ** _COMMAND_LENGTH_BITS if not isinstance(button_index, int): raise ValueError( "expected {}-bit unsigned integer as button index, got {!r}".format( _BUTTON_INDEX_LENGTH_BITS, button_index ) ) if button_index < 0: raise ValueError( "button index must not be negative (got {!r})".format(button_index) ) if button_index >= 2 ** _BUTTON_INDEX_LENGTH_BITS: raise ValueError( "button index must not exceed {} ({}-bit unsigned integer), got {!r}".format( 2 ** _BUTTON_INDEX_LENGTH_BITS, _BUTTON_INDEX_LENGTH_BITS, button_index, ) ) _cc1101_transmit( _encode_message( (self._address << _COMMAND_LENGTH_BITS | command) << _BUTTON_INDEX_LENGTH_BITS | button_index ), power_setting=power_setting, ) def turn_on( self, button_index: int, power_setting: int = DEFAULT_POWER_SETTING, ) -> None: """ Consult section "Table 39: Optimum PATABLE Settings for Various Output Power Levels and Frequency Bands [...]" in CC1101's official documentation for `power_setting`. """ self._send_command( command=0b01, button_index=button_index, power_setting=power_setting, ) def turn_off( self, button_index: int, power_setting: int = DEFAULT_POWER_SETTING, ) -> None: self._send_command( command=0b00, button_index=button_index, power_setting=power_setting, )