Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cc1101 radio transmitter component #6300

Draft
wants to merge 43 commits into
base: dev
Choose a base branch
from
Draft

Conversation

gabest11
Copy link
Contributor

@gabest11 gabest11 commented Feb 28, 2024

What does this implement/fix?

Texas Instruments CC1101 transceiver component.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • [ x] New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Other

Related issue or feature (if applicable): fixes

Pull request in esphome-docs with documentation (if applicable): esphome/esphome-docs#3897

Test Environment

  • [x ] ESP32
  • [ x] ESP32 IDF
  • [ x] ESP8266
  • RP2040
  • BK72xx
  • RTL87xx

Example entry for config.yaml:

# Example config.yaml

substitutions:
  device_name: cc1101

esphome:
  name: ${device_name}

esp32:
  board: nodemcu-32s
  variant: esp32
  framework:
    type: arduino
#  framework:
#    type: esp-idf
#    version: recommended

wifi:
  ssid: !secret wifi_name
  password: !secret wifi_pass

logger:
  level: DEBUG

ota:
  password: !secret every_password

spi:
  clk_pin: GPIO18
  miso_pin: GPIO19
  mosi_pin: GPIO23

 cc1101:
  id: transceiver
  cs_pin: GPIO5
  bandwidth: 200
  frequency: 433920
  rssi:
    name: "${device_name} rssi"
  lqi:
    name: "${device_name} lqi"
  
remote_transmitter:
  pin: GPIO32  # GDO0
  carrier_duty_percent: 100%

remote_receiver:
  pin: GPIO33  # GDO2
  dump:
    - rc_switch
    # - raw
  # Settings to optimize recognition of RF devices
  tolerance: 50%
  #buffer_size: 2kb
  filter: 250us
  idle: 4ms

api:
  services:
    - service: 'remote_transmit'
      variables:
        code: string
      then:
        - remote_transmitter.transmit_cc1101:
            code: !lambda 'return code.c_str();'
            protocol:
              pulse_length: 420
              sync: [1,31]
              zero: [1,3]
              one: [3,1]
              inverted: true
            repeat:
              times: 10

#mqtt:
#  on_json_message:
#    topic: "${device_name}/remote_transmit"
#    then:
#      - remote_transmitter.transmit_cc1101:
#          code: !lambda |-
#            if(x.containsKey("code")) return x["code"];
#            return "111111111111111111111111";
#          protocol:
#            pulse_length: 420
#            sync: [1,31]
#            zero: [1,3]
#            one: [3,1]
#            inverted: false
#          repeat:
#            times: 10
#      - cc1101.end_tx: transceiver

button:
  - platform: template
    name: "${device_name} gate"
    on_press:
      - remote_transmitter.transmit_cc1101:
          code: '0111000110010011110110010100011111110001001011110111'
          protocol:
            pulse_length: 434
            sync: [1,6]
            zero: [1,2]
            one: [2,1]
            inverted: true
          repeat:
            times: 10

binary_sensor:
  - platform: remote_receiver
    name: "${device_name} window"
    rc_switch_raw:
      code: '110111110001111011100110'
      protocol:
        pulse_length: 420
        sync: [1,31]
        zero: [1,3]
        one: [3,1]
        inverted: false
    filters:
      - delayed_off: 1000ms

Checklist:

  • [x ] The code change is tested and works locally.
  • [x ] Tests have been added to verify that the new code works (under tests/ folder).

If user exposed functionality or configuration variables are added/changed:

@probot-esphome
Copy link

Hey there @gabest11,
Thanks for submitting this pull request! Can you add yourself as a codeowner for this integration? This way we can notify you if a bug report for this integration is reported.
In __init__.py of the integration, please add:

CODEOWNERS = ["@gabest11"]

And run script/build_codeowners.py

(message by NeedsCodeownersLabel)

@codecov-commenter
Copy link

codecov-commenter commented Feb 28, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 53.90%. Comparing base (4d8b5ed) to head (627e0dd).
Report is 702 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #6300      +/-   ##
==========================================
+ Coverage   53.70%   53.90%   +0.19%     
==========================================
  Files          50       50              
  Lines        9408     9623     +215     
  Branches     1654     1698      +44     
==========================================
+ Hits         5053     5187     +134     
- Misses       4056     4112      +56     
- Partials      299      324      +25     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@gabest11
Copy link
Contributor Author

"Files Changed", top entry: "This CODEOWNERS file contains errors" Any idea what it means?

Copy link
Member

@jesserockz jesserockz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting this into the sensor component type is wrong. It should be a top level component. To introduce other radio transmitters like these, we probably need to do a refactor of the remote_* components first to allow better integration between them. THe user should not have to specifically call start/stop, but simply transmit and it should handle that itself.

@esphome
Copy link

esphome bot commented Feb 29, 2024

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

Comment on lines 10 to 107
static const uint32_t CC1101_IOCFG2 = 0x00; // GDO2 output pin configuration
static const uint32_t CC1101_IOCFG1 = 0x01; // GDO1 output pin configuration
static const uint32_t CC1101_IOCFG0 = 0x02; // GDO0 output pin configuration
static const uint32_t CC1101_FIFOTHR = 0x03; // RX FIFO and TX FIFO thresholds
static const uint32_t CC1101_SYNC1 = 0x04; // Sync word, high INT8U
static const uint32_t CC1101_SYNC0 = 0x05; // Sync word, low INT8U
static const uint32_t CC1101_PKTLEN = 0x06; // Packet length
static const uint32_t CC1101_PKTCTRL1 = 0x07; // Packet automation control
static const uint32_t CC1101_PKTCTRL0 = 0x08; // Packet automation control
static const uint32_t CC1101_ADDR = 0x09; // Device address
static const uint32_t CC1101_CHANNR = 0x0A; // Channel number
static const uint32_t CC1101_FSCTRL1 = 0x0B; // Frequency synthesizer control
static const uint32_t CC1101_FSCTRL0 = 0x0C; // Frequency synthesizer control
static const uint32_t CC1101_FREQ2 = 0x0D; // Frequency control word, high INT8U
static const uint32_t CC1101_FREQ1 = 0x0E; // Frequency control word, middle INT8U
static const uint32_t CC1101_FREQ0 = 0x0F; // Frequency control word, low INT8U
static const uint32_t CC1101_MDMCFG4 = 0x10; // Modem configuration
static const uint32_t CC1101_MDMCFG3 = 0x11; // Modem configuration
static const uint32_t CC1101_MDMCFG2 = 0x12; // Modem configuration
static const uint32_t CC1101_MDMCFG1 = 0x13; // Modem configuration
static const uint32_t CC1101_MDMCFG0 = 0x14; // Modem configuration
static const uint32_t CC1101_DEVIATN = 0x15; // Modem deviation setting
static const uint32_t CC1101_MCSM2 = 0x16; // Main Radio Control State Machine configuration
static const uint32_t CC1101_MCSM1 = 0x17; // Main Radio Control State Machine configuration
static const uint32_t CC1101_MCSM0 = 0x18; // Main Radio Control State Machine configuration
static const uint32_t CC1101_FOCCFG = 0x19; // Frequency Offset Compensation configuration
static const uint32_t CC1101_BSCFG = 0x1A; // Bit Synchronization configuration
static const uint32_t CC1101_AGCCTRL2 = 0x1B; // AGC control
static const uint32_t CC1101_AGCCTRL1 = 0x1C; // AGC control
static const uint32_t CC1101_AGCCTRL0 = 0x1D; // AGC control
static const uint32_t CC1101_WOREVT1 = 0x1E; // High INT8U Event 0 timeout
static const uint32_t CC1101_WOREVT0 = 0x1F; // Low INT8U Event 0 timeout
static const uint32_t CC1101_WORCTRL = 0x20; // Wake On Radio control
static const uint32_t CC1101_FREND1 = 0x21; // Front end RX configuration
static const uint32_t CC1101_FREND0 = 0x22; // Front end TX configuration
static const uint32_t CC1101_FSCAL3 = 0x23; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL2 = 0x24; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL1 = 0x25; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL0 = 0x26; // Frequency synthesizer calibration
static const uint32_t CC1101_RCCTRL1 = 0x27; // RC oscillator configuration
static const uint32_t CC1101_RCCTRL0 = 0x28; // RC oscillator configuration
static const uint32_t CC1101_FSTEST = 0x29; // Frequency synthesizer calibration control
static const uint32_t CC1101_PTEST = 0x2A; // Production test
static const uint32_t CC1101_AGCTEST = 0x2B; // AGC test
static const uint32_t CC1101_TEST2 = 0x2C; // Various test settings
static const uint32_t CC1101_TEST1 = 0x2D; // Various test settings
static const uint32_t CC1101_TEST0 = 0x2E; // Various test settings

// CC1101 Strobe commands
static const uint32_t CC1101_SRES = 0x30; // Reset chip.
static const uint32_t CC1101_SFSTXON = 0x31; // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
// If in RX/TX: Go to a wait state where only the synthesizer is
// running (for quick RX / TX turnaround).
static const uint32_t CC1101_SXOFF = 0x32; // Turn off crystal oscillator.
static const uint32_t CC1101_SCAL = 0x33; // Calibrate frequency synthesizer and turn it off
// (enables quick start).
static const uint32_t CC1101_SRX = 0x34; // Enable RX. Perform calibration first if coming from IDLE and
// MCSM0.FS_AUTOCAL=1.
static const uint32_t CC1101_STX = 0x35; // In IDLE state: Enable TX. Perform calibration first if
// MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
// Only go to TX if channel is clear.
static const uint32_t CC1101_SIDLE = 0x36; // Exit RX / TX, turn off frequency synthesizer and exit
// Wake-On-Radio mode if applicable.
static const uint32_t CC1101_SAFC = 0x37; // Perform AFC adjustment of the frequency synthesizer
static const uint32_t CC1101_SWOR = 0x38; // Start automatic RX polling sequence (Wake-on-Radio)
static const uint32_t CC1101_SPWD = 0x39; // Enter power down mode when CSn goes high.
static const uint32_t CC1101_SFRX = 0x3A; // Flush the RX FIFO buffer.
static const uint32_t CC1101_SFTX = 0x3B; // Flush the TX FIFO buffer.
static const uint32_t CC1101_SWORRST = 0x3C; // Reset real time clock.
static const uint32_t CC1101_SNOP = 0x3D; // No operation. May be used to pad strobe commands to two
// INT8Us for simpler software.
// CC1101 STATUS REGSITER
static const uint32_t CC1101_PARTNUM = 0x30;
static const uint32_t CC1101_VERSION = 0x31;
static const uint32_t CC1101_FREQEST = 0x32;
static const uint32_t CC1101_LQI = 0x33;
static const uint32_t CC1101_RSSI = 0x34;
static const uint32_t CC1101_MARCSTATE = 0x35;
static const uint32_t CC1101_WORTIME1 = 0x36;
static const uint32_t CC1101_WORTIME0 = 0x37;
static const uint32_t CC1101_PKTSTATUS = 0x38;
static const uint32_t CC1101_VCO_VC_DAC = 0x39;
static const uint32_t CC1101_TXBYTES = 0x3A;
static const uint32_t CC1101_RXBYTES = 0x3B;

// CC1101 PATABLE,TXFIFO,RXFIFO
static const uint32_t CC1101_PATABLE = 0x3E;
static const uint32_t CC1101_TXFIFO = 0x3F;
static const uint32_t CC1101_RXFIFO = 0x3F;

static const uint32_t CC1101_WRITE_BURST = 0x40; // write burst
static const uint32_t CC1101_READ_SINGLE = 0x80; // read single
static const uint32_t CC1101_READ_BURST = 0xC0; // read burst
static const uint32_t CC1101_BYTES_IN_RXFIFO = 0x7F; // byte number in RXfifo

static const uint32_t CC1101_MARCSTATE_TX = 0x13;
static const uint32_t CC1101_MARCSTATE_TX_END = 0x14;
static const uint32_t CC1101_MARCSTATE_RXTX_SWITCH = 0x15;
Copy link
Contributor

@PiuPiuson PiuPiuson Mar 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider converting these to constexpr - the compiler will probably optimise them anyway but why not force it!

Suggested change
static const uint32_t CC1101_IOCFG2 = 0x00; // GDO2 output pin configuration
static const uint32_t CC1101_IOCFG1 = 0x01; // GDO1 output pin configuration
static const uint32_t CC1101_IOCFG0 = 0x02; // GDO0 output pin configuration
static const uint32_t CC1101_FIFOTHR = 0x03; // RX FIFO and TX FIFO thresholds
static const uint32_t CC1101_SYNC1 = 0x04; // Sync word, high INT8U
static const uint32_t CC1101_SYNC0 = 0x05; // Sync word, low INT8U
static const uint32_t CC1101_PKTLEN = 0x06; // Packet length
static const uint32_t CC1101_PKTCTRL1 = 0x07; // Packet automation control
static const uint32_t CC1101_PKTCTRL0 = 0x08; // Packet automation control
static const uint32_t CC1101_ADDR = 0x09; // Device address
static const uint32_t CC1101_CHANNR = 0x0A; // Channel number
static const uint32_t CC1101_FSCTRL1 = 0x0B; // Frequency synthesizer control
static const uint32_t CC1101_FSCTRL0 = 0x0C; // Frequency synthesizer control
static const uint32_t CC1101_FREQ2 = 0x0D; // Frequency control word, high INT8U
static const uint32_t CC1101_FREQ1 = 0x0E; // Frequency control word, middle INT8U
static const uint32_t CC1101_FREQ0 = 0x0F; // Frequency control word, low INT8U
static const uint32_t CC1101_MDMCFG4 = 0x10; // Modem configuration
static const uint32_t CC1101_MDMCFG3 = 0x11; // Modem configuration
static const uint32_t CC1101_MDMCFG2 = 0x12; // Modem configuration
static const uint32_t CC1101_MDMCFG1 = 0x13; // Modem configuration
static const uint32_t CC1101_MDMCFG0 = 0x14; // Modem configuration
static const uint32_t CC1101_DEVIATN = 0x15; // Modem deviation setting
static const uint32_t CC1101_MCSM2 = 0x16; // Main Radio Control State Machine configuration
static const uint32_t CC1101_MCSM1 = 0x17; // Main Radio Control State Machine configuration
static const uint32_t CC1101_MCSM0 = 0x18; // Main Radio Control State Machine configuration
static const uint32_t CC1101_FOCCFG = 0x19; // Frequency Offset Compensation configuration
static const uint32_t CC1101_BSCFG = 0x1A; // Bit Synchronization configuration
static const uint32_t CC1101_AGCCTRL2 = 0x1B; // AGC control
static const uint32_t CC1101_AGCCTRL1 = 0x1C; // AGC control
static const uint32_t CC1101_AGCCTRL0 = 0x1D; // AGC control
static const uint32_t CC1101_WOREVT1 = 0x1E; // High INT8U Event 0 timeout
static const uint32_t CC1101_WOREVT0 = 0x1F; // Low INT8U Event 0 timeout
static const uint32_t CC1101_WORCTRL = 0x20; // Wake On Radio control
static const uint32_t CC1101_FREND1 = 0x21; // Front end RX configuration
static const uint32_t CC1101_FREND0 = 0x22; // Front end TX configuration
static const uint32_t CC1101_FSCAL3 = 0x23; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL2 = 0x24; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL1 = 0x25; // Frequency synthesizer calibration
static const uint32_t CC1101_FSCAL0 = 0x26; // Frequency synthesizer calibration
static const uint32_t CC1101_RCCTRL1 = 0x27; // RC oscillator configuration
static const uint32_t CC1101_RCCTRL0 = 0x28; // RC oscillator configuration
static const uint32_t CC1101_FSTEST = 0x29; // Frequency synthesizer calibration control
static const uint32_t CC1101_PTEST = 0x2A; // Production test
static const uint32_t CC1101_AGCTEST = 0x2B; // AGC test
static const uint32_t CC1101_TEST2 = 0x2C; // Various test settings
static const uint32_t CC1101_TEST1 = 0x2D; // Various test settings
static const uint32_t CC1101_TEST0 = 0x2E; // Various test settings
// CC1101 Strobe commands
static const uint32_t CC1101_SRES = 0x30; // Reset chip.
static const uint32_t CC1101_SFSTXON = 0x31; // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
// If in RX/TX: Go to a wait state where only the synthesizer is
// running (for quick RX / TX turnaround).
static const uint32_t CC1101_SXOFF = 0x32; // Turn off crystal oscillator.
static const uint32_t CC1101_SCAL = 0x33; // Calibrate frequency synthesizer and turn it off
// (enables quick start).
static const uint32_t CC1101_SRX = 0x34; // Enable RX. Perform calibration first if coming from IDLE and
// MCSM0.FS_AUTOCAL=1.
static const uint32_t CC1101_STX = 0x35; // In IDLE state: Enable TX. Perform calibration first if
// MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
// Only go to TX if channel is clear.
static const uint32_t CC1101_SIDLE = 0x36; // Exit RX / TX, turn off frequency synthesizer and exit
// Wake-On-Radio mode if applicable.
static const uint32_t CC1101_SAFC = 0x37; // Perform AFC adjustment of the frequency synthesizer
static const uint32_t CC1101_SWOR = 0x38; // Start automatic RX polling sequence (Wake-on-Radio)
static const uint32_t CC1101_SPWD = 0x39; // Enter power down mode when CSn goes high.
static const uint32_t CC1101_SFRX = 0x3A; // Flush the RX FIFO buffer.
static const uint32_t CC1101_SFTX = 0x3B; // Flush the TX FIFO buffer.
static const uint32_t CC1101_SWORRST = 0x3C; // Reset real time clock.
static const uint32_t CC1101_SNOP = 0x3D; // No operation. May be used to pad strobe commands to two
// INT8Us for simpler software.
// CC1101 STATUS REGSITER
static const uint32_t CC1101_PARTNUM = 0x30;
static const uint32_t CC1101_VERSION = 0x31;
static const uint32_t CC1101_FREQEST = 0x32;
static const uint32_t CC1101_LQI = 0x33;
static const uint32_t CC1101_RSSI = 0x34;
static const uint32_t CC1101_MARCSTATE = 0x35;
static const uint32_t CC1101_WORTIME1 = 0x36;
static const uint32_t CC1101_WORTIME0 = 0x37;
static const uint32_t CC1101_PKTSTATUS = 0x38;
static const uint32_t CC1101_VCO_VC_DAC = 0x39;
static const uint32_t CC1101_TXBYTES = 0x3A;
static const uint32_t CC1101_RXBYTES = 0x3B;
// CC1101 PATABLE,TXFIFO,RXFIFO
static const uint32_t CC1101_PATABLE = 0x3E;
static const uint32_t CC1101_TXFIFO = 0x3F;
static const uint32_t CC1101_RXFIFO = 0x3F;
static const uint32_t CC1101_WRITE_BURST = 0x40; // write burst
static const uint32_t CC1101_READ_SINGLE = 0x80; // read single
static const uint32_t CC1101_READ_BURST = 0xC0; // read burst
static const uint32_t CC1101_BYTES_IN_RXFIFO = 0x7F; // byte number in RXfifo
static const uint32_t CC1101_MARCSTATE_TX = 0x13;
static const uint32_t CC1101_MARCSTATE_TX_END = 0x14;
static const uint32_t CC1101_MARCSTATE_RXTX_SWITCH = 0x15;
static constexpr uint32_t CC1101_IOCFG2 = 0x00; // GDO2 output pin configuration
static constexpr uint32_t CC1101_IOCFG1 = 0x01; // GDO1 output pin configuration
static constexpr uint32_t CC1101_IOCFG0 = 0x02; // GDO0 output pin configuration
static constexpr uint32_t CC1101_FIFOTHR = 0x03; // RX FIFO and TX FIFO thresholds
static constexpr uint32_t CC1101_SYNC1 = 0x04; // Sync word, high INT8U
static constexpr uint32_t CC1101_SYNC0 = 0x05; // Sync word, low INT8U
static constexpr uint32_t CC1101_PKTLEN = 0x06; // Packet length
static constexpr uint32_t CC1101_PKTCTRL1 = 0x07; // Packet automation control
static constexpr uint32_t CC1101_PKTCTRL0 = 0x08; // Packet automation control
static constexpr uint32_t CC1101_ADDR = 0x09; // Device address
static constexpr uint32_t CC1101_CHANNR = 0x0A; // Channel number
static constexpr uint32_t CC1101_FSCTRL1 = 0x0B; // Frequency synthesizer control
static constexpr uint32_t CC1101_FSCTRL0 = 0x0C; // Frequency synthesizer control
static constexpr uint32_t CC1101_FREQ2 = 0x0D; // Frequency control word, high INT8U
static constexpr uint32_t CC1101_FREQ1 = 0x0E; // Frequency control word, middle INT8U
static constexpr uint32_t CC1101_FREQ0 = 0x0F; // Frequency control word, low INT8U
static constexpr uint32_t CC1101_MDMCFG4 = 0x10; // Modem configuration
static constexpr uint32_t CC1101_MDMCFG3 = 0x11; // Modem configuration
static constexpr uint32_t CC1101_MDMCFG2 = 0x12; // Modem configuration
static constexpr uint32_t CC1101_MDMCFG1 = 0x13; // Modem configuration
static constexpr uint32_t CC1101_MDMCFG0 = 0x14; // Modem configuration
static constexpr uint32_t CC1101_DEVIATN = 0x15; // Modem deviation setting
static constexpr uint32_t CC1101_MCSM2 = 0x16; // Main Radio Control State Machine configuration
static constexpr uint32_t CC1101_MCSM1 = 0x17; // Main Radio Control State Machine configuration
static constexpr uint32_t CC1101_MCSM0 = 0x18; // Main Radio Control State Machine configuration
static constexpr uint32_t CC1101_FOCCFG = 0x19; // Frequency Offset Compensation configuration
static constexpr uint32_t CC1101_BSCFG = 0x1A; // Bit Synchronization configuration
static constexpr uint32_t CC1101_AGCCTRL2 = 0x1B; // AGC control
static constexpr uint32_t CC1101_AGCCTRL1 = 0x1C; // AGC control
static constexpr uint32_t CC1101_AGCCTRL0 = 0x1D; // AGC control
static constexpr uint32_t CC1101_WOREVT1 = 0x1E; // High INT8U Event 0 timeout
static constexpr uint32_t CC1101_WOREVT0 = 0x1F; // Low INT8U Event 0 timeout
static constexpr uint32_t CC1101_WORCTRL = 0x20; // Wake On Radio control
static constexpr uint32_t CC1101_FREND1 = 0x21; // Front end RX configuration
static constexpr uint32_t CC1101_FREND0 = 0x22; // Front end TX configuration
static constexpr uint32_t CC1101_FSCAL3 = 0x23; // Frequency synthesizer calibration
static constexpr uint32_t CC1101_FSCAL2 = 0x24; // Frequency synthesizer calibration
static constexpr uint32_t CC1101_FSCAL1 = 0x25; // Frequency synthesizer calibration
static constexpr uint32_t CC1101_FSCAL0 = 0x26; // Frequency synthesizer calibration
static constexpr uint32_t CC1101_RCCTRL1 = 0x27; // RC oscillator configuration
static constexpr uint32_t CC1101_RCCTRL0 = 0x28; // RC oscillator configuration
static constexpr uint32_t CC1101_FSTEST = 0x29; // Frequency synthesizer calibration control
static constexpr uint32_t CC1101_PTEST = 0x2A; // Production test
static constexpr uint32_t CC1101_AGCTEST = 0x2B; // AGC test
static constexpr uint32_t CC1101_TEST2 = 0x2C; // Various test settings
static constexpr uint32_t CC1101_TEST1 = 0x2D; // Various test settings
static constexpr uint32_t CC1101_TEST0 = 0x2E; // Various test settings
// CC1101 Strobe commands
static constexpr uint32_t CC1101_SRES = 0x30; // Reset chip.
static constexpr uint32_t CC1101_SFSTXON = 0x31; // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
// If in RX/TX: Go to a wait state where only the synthesizer is
// running (for quick RX / TX turnaround).
static constexpr uint32_t CC1101_SXOFF = 0x32; // Turn off crystal oscillator.
static constexpr uint32_t CC1101_SCAL = 0x33; // Calibrate frequency synthesizer and turn it off
// (enables quick start).
static constexpr uint32_t CC1101_SRX = 0x34; // Enable RX. Perform calibration first if coming from IDLE and
// MCSM0.FS_AUTOCAL=1.
static constexpr uint32_t CC1101_STX = 0x35; // In IDLE state: Enable TX. Perform calibration first if
// MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
// Only go to TX if channel is clear.
static constexpr uint32_t CC1101_SIDLE = 0x36; // Exit RX / TX, turn off frequency synthesizer and exit
// Wake-On-Radio mode if applicable.
static constexpr uint32_t CC1101_SAFC = 0x37; // Perform AFC adjustment of the frequency synthesizer
static constexpr uint32_t CC1101_SWOR = 0x38; // Start automatic RX polling sequence (Wake-on-Radio)
static constexpr uint32_t CC1101_SPWD = 0x39; // Enter power down mode when CSn goes high.
static constexpr uint32_t CC1101_SFRX = 0x3A; // Flush the RX FIFO buffer.
static constexpr uint32_t CC1101_SFTX = 0x3B; // Flush the TX FIFO buffer.
static constexpr uint32_t CC1101_SWORRST = 0x3C; // Reset real time clock.
static constexpr uint32_t CC1101_SNOP = 0x3D; // No operation. May be used to pad strobe commands to two
// INT8Us for simpler software.
// CC1101 STATUS REGSITER
static constexpr uint32_t CC1101_PARTNUM = 0x30;
static constexpr uint32_t CC1101_VERSION = 0x31;
static constexpr uint32_t CC1101_FREQEST = 0x32;
static constexpr uint32_t CC1101_LQI = 0x33;
static constexpr uint32_t CC1101_RSSI = 0x34;
static constexpr uint32_t CC1101_MARCSTATE = 0x35;
static constexpr uint32_t CC1101_WORTIME1 = 0x36;
static constexpr uint32_t CC1101_WORTIME0 = 0x37;
static constexpr uint32_t CC1101_PKTSTATUS = 0x38;
static constexpr uint32_t CC1101_VCO_VC_DAC = 0x39;
static constexpr uint32_t CC1101_TXBYTES = 0x3A;
static constexpr uint32_t CC1101_RXBYTES = 0x3B;
// CC1101 PATABLE,TXFIFO,RXFIFO
static constexpr uint32_t CC1101_PATABLE = 0x3E;
static constexpr uint32_t CC1101_TXFIFO = 0x3F;
static constexpr uint32_t CC1101_RXFIFO = 0x3F;
static constexpr uint32_t CC1101_WRITE_BURST = 0x40; // write burst
static constexpr uint32_t CC1101_READ_SINGLE = 0x80; // read single
static constexpr uint32_t CC1101_READ_BURST = 0xC0; // read burst
static constexpr uint32_t CC1101_BYTES_IN_RXFIFO = 0x7F; // byte number in RXfifo
static constexpr uint32_t CC1101_MARCSTATE_TX = 0x13;
static constexpr uint32_t CC1101_MARCSTATE_TX_END = 0x14;
static constexpr uint32_t CC1101_MARCSTATE_RXTX_SWITCH = 0x15;

@gabest11
Copy link
Contributor Author

gabest11 commented Mar 1, 2024

Yea, compilers just put the value into the instruction operand directly, these things aren't stored anywhere.

@gabest11
Copy link
Contributor Author

gabest11 commented Mar 1, 2024

I started working on the CC1101 too (over half a year ago) but was told that the existing remote receiver/transmitter code needs refactoring. So I waited with implementing the RF stuff but already got the internal temperature sensor of the CC1101 to work with ESPHome. Maybe you can use anything from that for your own CC1101 component. https://github.com/Mat931/esphome/tree/cc1101

I think I killed a pin on my esp32 when trying to do the temperature sensing. First copied the relevant code and only showed 0.075v, then tried yours, that worked perfectly, then flashed back mine and mocked around more, and it's dead. Tried just an adc on it with nothing else, it's completelty dead. But the rest of the board is fine. Now I'm scared to do anything :)

GPO0 has to be assigned to yet another component, adc, remote_transmitter, cc1101, three in total. All try to control it. Not sure if that's going to work.

@gabest11
Copy link
Contributor Author

gabest11 commented Mar 1, 2024

The pin has miraculously recovered. And I got the temperature sensor working just alone in a separate yaml.

sensor:
  - platform: adc
    pin: GPIO32
    id: gdo0_adc
    update_interval: 60s

spi:
  clk_pin: GPIO18
  miso_pin: GPIO19
  mosi_pin: GPIO23

spi_device:
    id: spidev
    cs_pin: GPIO5
    data_rate: 1MHz
    mode: 0
    bit_order: msb_first

interval:
  - interval: 5s
    then:
    - lambda: |-

        auto strobe = [&](uint8_t reg) {
          id(spidev).enable();
          id(spidev).write_byte(reg);
          id(spidev).disable();          
        };

        auto write_reg = [&](uint8_t reg, uint8_t value) {
          id(spidev).enable();
          id(spidev).write_byte(reg);
          id(spidev).write_byte(value);
          id(spidev).disable();
        };

        auto read_reg = [&](uint8_t reg) -> uint8_t {
          id(spidev).enable();
          id(spidev).write_byte(reg);
          uint8_t value = id(spidev).transfer_byte(0xFF);
          id(spidev).disable();
          return value;
        };

        auto set_mode = [&](uint8_t mode, uint8_t marcstate = 0x01) {
          strobe(mode);
          for (uint16_t timeout = 5000; (read_reg(0xF5) & 0x1f) != marcstate && timeout > 0; timeout--) { delayMicroseconds(1); }
          delayMicroseconds(100);
        };

        static const uint8_t IOCFG0 = 0x02;
        static const uint8_t PTEST = 0x2A;
        static const uint8_t SRES = 0x30;
        static const uint8_t SIDLE = 0x36;
        static const uint8_t SFRX = 0x3A;
        static const uint8_t SFTX = 0x3B;

        id(spidev).enable();
        delayMicroseconds(10);
        id(spidev).disable();
        delayMicroseconds(40);
        strobe(SRES);
        delay(1);

        strobe(SFTX); // Flush TX FIFO
        delayMicroseconds(100);
        strobe(SFRX); // Flush RX FIFO
        delayMicroseconds(100);

        uint8_t part_number = read_reg(0xF0);
        uint8_t chip_version = read_reg(0xF1);
        ESP_LOGD("${plug_name}", "part_number = %02x, chip_version = %02x", part_number, chip_version);

        // this->temperature_ = this->get_temperature(1);

        set_mode(SIDLE);

        write_reg(IOCFG0, 0x2F);
        float voltage_low = id(gdo0_adc).sample();
        write_reg(IOCFG0, 0x6F);
        float voltage_high = id(gdo0_adc).sample();
        ESP_LOGD("${plug_name}", "ADC low = %f high = %f", voltage_low, voltage_high);

        write_reg(IOCFG0, 0x80); // Analog temperature output on GDO0
        write_reg(PTEST, 0xBF); // Enable temperature sensor

        delay(50);

        float voltage = 0.0f;
        int successful_samples = 0;

        for (uint8_t i = 0, num_samples = 10; i < num_samples; i++) {
          float voltage_reading = id(gdo0_adc).sample();
          ESP_LOGD("${plug_name}", "ADC voltage_reading = %f", voltage_reading);
          if (std::isfinite(voltage_reading) && voltage_reading > 0.6 &&
              voltage_reading < 1.0) {
            voltage += voltage_reading;
            successful_samples++;
          }
        }

        if (successful_samples) {
          voltage = voltage * 1000.0f / static_cast<float>(successful_samples);
        }
        else {
          voltage = NAN;
        }

        auto mapvalue = [&](float x, float in_min, float in_max, float out_min, float out_max) -> float {
          return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
        };

        float t = 0;
        
        if (voltage >= 651 && voltage < 747) {
          t = mapvalue(voltage, 651, 747, -40, 0);
        }
        else if (voltage >= 747 && voltage < 847) {
          t = mapvalue(voltage, 747, 847, 0, 40);
        }
        else if (voltage >= 847 && voltage < 945) {
          t = mapvalue(voltage, 847, 945, 40, 80);
        }
        else {
          t = NAN;
        }

        ESP_LOGD("${plug_name}", "ADC voltage = %f, temperature = %.2f", voltage, t);

        write_reg(PTEST, 0x7F); // Disable temperature sensor
        write_reg(IOCFG0, 0x80); // Restore GDO0 pin mode

        set_mode(SIDLE);

[22:26:15][D][analogsensor2:105]: part_number = 00, chip_version = 14
[22:26:15][D][analogsensor2:117]: ADC low = 0.075000 high = 1.045000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.806000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.809000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.800000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.806000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.806000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.806000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.806000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.806000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.809000
[22:26:15][D][analogsensor2:129]: ADC voltage_reading = 0.806000
[22:26:15][D][analogsensor2:163]: ADC voltage = 805.999939, temperature = 23.60

It measures about +2C higher than what I have in the room.

Actually this lambda code loophole is so embarrassing, the whole thing could be used without a component, just through spi/spi_device.

@gabest11
Copy link
Contributor Author

gabest11 commented Mar 1, 2024

Can't join the discord channel btw.

@gabest11
Copy link
Contributor Author

gabest11 commented Mar 2, 2024

remote_transmitter does not want to work together with the ADC component for some reason. ESP32. I have GDO0 on 32, GDO2 on 33. With ADC on 32 I can read the temperature. But ADC on 32, 35, 36, or any other pin in the ADC1 group (wifi and ADC2 does not work together) and transmission stops working. Just by having the ADC component there, not even using it.

Noticed one more thing, until I re-plug the usb power connector, it stays in this broken state. Just flashing a new firmware without ADC and rebooting does not fix it.

@nagyrobi
Copy link
Member

nagyrobi commented Mar 7, 2024

fyi esphome/feature-requests#2638

@gabest11
Copy link
Contributor Author

gabest11 commented Mar 7, 2024

I have not tried anything other than 433.92, but this should work on all frequencies.

@LorbusChris
Copy link

LorbusChris commented May 18, 2024

@gabest11 thank you for this! For access to the discord channel you first need to join the ESPhome server: https://discord.com/invite/KhAMKrd

Wondering what the state of this is, would be great to get this merged!

@fightforlife
Copy link
Contributor

fightforlife commented May 27, 2024

Latest dev seems to introduce new printf handling and leading to some compilation errors.
I fixed the compilation errors for printf in gabest11#1 (PR to this PR)

P.S.: Love this component! Could be really useful for small remote sensors together with #4954

Fixing some printf errors in latest dev compilation
Revert "Fixing some printf errors in latest dev compilation"
Replace (u)int32_t with regular int, to avoid compilation problems on idf 5+.
@fightforlife
Copy link
Contributor

fightforlife commented Jun 3, 2024

@gabest11 can you add MULTI_CONF = True to the python? It would be cool to use multiple CC1101 on one host.
e.g.:

cc1101:
  - id: transceiver
    cs_pin: GPIO15
    bandwidth: 200
    frequency: 433920

  - id: transceiver2
    cs_pin: GPIO33
    bandwidth: 200
    frequency: 868300

@swoboda1337
Copy link
Contributor

ld be a top level component. To introduce other radio transmitters like these, we probably need to do a refactor of the remote_* components first to allow better integration between them. The user should not have to specifically call start/

I also have an rf component that I would like to push: (https://github.com/swoboda1337/sx127x-esphome). Anyone working on this API change to start/stop transmitters automatically?

@swoboda1337
Copy link
Contributor

ld be a top level component. To introduce other radio transmitters like these, we probably need to do a refactor of the remote_* components first to allow better integration between them. The user should not have to specifically call start/

I also have an rf component that I would like to push: (https://github.com/swoboda1337/sx127x-esphome). Anyone working on this API change to start/stop transmitters automatically?

I put up a draft PR (#7000) so radios can automatically enable and disable tx. The radio component would be responsible for registering a listener. Remote transmitter will call the radio listener at the beginning and end of a transmission. This way the user wont have to worry about manually starting and stopping tx. Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants