123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- 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,
- )
|