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

Add RF Transceiver 868MHz CC1101 #59

Open
christiaandouma opened this issue Feb 13, 2019 · 32 comments
Open

Add RF Transceiver 868MHz CC1101 #59

christiaandouma opened this issue Feb 13, 2019 · 32 comments

Comments

@christiaandouma
Copy link

What new integration would you wish to have?
Would it be able to add RF Transceiver 868MHz CC1101?

If possible, provide a link to an existing library for the integration:*
https://github.com/incmve/Itho-WIFI-remote

Please describe your use case for this integration and alternatives you've tried:*
I currently made a temp sensor send via mqtt and recieive command for the rf868mhz from mqtt.
This Will send a rf signaal to the itho ventilation

I want to use esphomelib as i think this a lot cleaner.

Additional context:
Thx.

@OttoWinter OttoWinter transferred this issue from esphome/esphome-core Feb 13, 2019
@Emacee
Copy link

Emacee commented Sep 21, 2019

For me this would also be really nice! Unfortunately I don’t have enough coding experience to get us any further, maybe someone else is able and willing to jump in?

@jvanderneutstulen
Copy link

I have been working a itho fan component, which works for my Itho Ecofan. I you want to try it, you can check out the itho-ecofanrft branch of my fork. Supports sending commands, and will report current fan speed.

Configuration example for esp8266:

spi:
    clk_pin: D5
    mosi_pin: D7
    miso_pin: D6

itho_ecofanrft:
    id: ecofan
    cs_pin: D8
    irq_pin: D2
    rf_address: "01:02:03"

fan:
   - platform: itho_ecofanrft
     name: "MV"

and for esp32:

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO23
  miso_pin: GPIO19

itho_ecofanrft:
  cs_pin: GPIO5
  irq_pin: GPIO2
  id: ecofan
  rf_address: "51:52:53"
  peer_rf_address: "50:49:48"

fan:
  - platform: itho_ecofanrft
    name: "Ventilation"

switch:
  - platform: template
    name: "Join Remote"
    turn_on_action:
      - itho_ecofanrft.join: ecofan

peer_rf_address is the rf address for the ventilation, when you leave it out, the component will log all the addresses it sees. My unit sends it status every 2 minutes. For the ventilation unit to accept commands you must send a join command after powercycling the unit. See last example how you can expose a "join switch".

@Emacee
Copy link

Emacee commented Oct 12, 2019

Nice work @jvanderneutstulen! I'm using the Hass.io add-on of ESPHome. I tried to add the Itho component included in your branch. However, I cannot find where the Hass.io add-on it stores its components so I cannot add your branch to have a look myself. How do you use your own branch?

@christiaandouma
Copy link
Author

Nice! I will try do setup a nodemcu with esphome to test this once i got the time

Thanks for the great work!

@jvanderneutstulen
Copy link

Nice work @jvanderneutstulen! I'm using the Hass.io add-on of ESPHome. I tried to add the Itho component included in your branch. However, I cannot find where the Hass.io add-on it stores its components so I cannot add your branch to have a look myself. How do you use your own branch?

You should a setup a dev using my fork (see https://esphome.io/guides/contributing.html#setting-up-development-environment) and compile/upload from there (for now). Then you can use the normal
HA esphome integration to discover the fan.

@christiaandouma
Copy link
Author

christiaandouma commented Oct 13, 2019

Trying to get IT to work but somehow IT doesn't work. Whats irq, where is IT Needed for. I could map the old PINS but irq i dont know.

I do see it in ha but it doesn't respond on high etc and join Actions

@jvanderneutstulen
Copy link

irq_pin should be the pin which is GDO2 (pin 6 on my module). It triggers an interrupt when the c1101 has received a packet.

@christiaandouma
Copy link
Author

christiaandouma commented Oct 13, 2019 via email

@jvanderneutstulen
Copy link

jvanderneutstulen commented Oct 13, 2019

No, when joining the fan should spin up briefly, I didn't see any RF message. My unit does send some sort of message on poweron, when it's accepting join commands. (Use loglevel VERY_VERBOSE to see the received packet payload.)

@christiaandouma
Copy link
Author

christiaandouma commented Oct 14, 2019 via email

@christiaandouma
Copy link
Author

christiaandouma commented Oct 23, 2019 via email

@jvanderneutstulen
Copy link

Can you post your configuration (without secrets)? And maybe some logs?

@christiaandouma
Copy link
Author

christiaandouma commented Oct 24, 2019 via email

@dbuezas
Copy link

dbuezas commented Nov 19, 2021

Three cc1101 at different frequencies on one single esp8266 transmitting & receiving.

All the preexisting door sensors, garage door (scary) and a bunch of switches and new cheap door sensors in my house use non-rolling codes and manchester encoding, so I was able to reuse the existing "remote_transmitter" and "remote_receiver" components and integrate everything together.

The trick here is that the lib I'm using puts the cc1101 in a "direct" mode so it works like the classic rf chips, but still allows to set the frequency in software. Also, multiple chips are all hooked on the same spi bus, and each uses 1 single extra pin both to transmit and receive the raw data, so the "mode" needs to be changed before and after transmitting.

Each cc1101 therefore needs two dedicated pins (chip select and "raw" data), plus the 3 spi pins used all chips at the same time. The d1 mini looks like a spider.
I'm really impressed by this chip, even the raw dump is quiet almost all the time and the range is quite good. Plus the frequency can be changed in software, which is amazing.

Note: there are two different board versions for 433 (red/blue) and 868 (green), each optimised for their frequency, but they both work in all frequencies (although with reduced range).

image

I'm using all of these


rf_gateway_cc1101.yaml

esphome:
  name: rf_gateway_cc1101
  platform: ESP8266
  board: d1_mini
  build_path: ./build/rf_gateway_cc1101
  includes:
    - rf_gateway_cc1101/custom_component.h
  libraries:
    - SPI
    - "SmartRC-CC1101-Driver-Lib"

packages:
  doors_package: !include rf_gateway_cc1101/433.325.yaml 
  rc_package: !include rf_gateway_cc1101/433.92.yaml
  r868_package: !include rf_gateway_cc1101/868.yaml

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

logger:
api:
ota:      

rf_gateway_cc1101/433.92.yaml

packages:
  three_btn_white_switch: !include 433.92.three-btn-white-switch.yaml
  door_sensor: !include 433.92.door_sensor.yaml
  rc: !include 433.92.rc.yaml
custom_component:
  - lambda: |-
      // chip 1 (red) - RC
      auto transciver_433_92 = new CC1101Transciver(D5, D6, D7, D3, D1, 158.03, 433.92);
      return {transciver_433_92};
    components:
      - id: transciver_433_92

remote_transmitter:
  - id: transmitter_rc
    pin: D1
    carrier_duty_percent: 100%

# note that the transmitter is defined first and the receiver last. This seems to let the pin on input mode at startup, which is what we want.

remote_receiver:
  - id: receiver_rc
    pin:
      # Don't use D3,D4,D8,TX, boot often fails.
      # Can't be D0 or GPIO17 b/c no interrupts
      # Can be D1,D2,D5,D6,D7,Rx
      number: D1
    dump:
      - raw
    tolerance: 50%
    filter: 35us
    idle: 2ms
    buffer_size: 1kb

The other two files for different frequencies:

  • rf_gateway_cc1101/433.325.yaml
  • rf_gateway_cc1101/868.yaml

are equivalent to this one. Only the CS (D3) and "data" pin (D1) change. (and the frequency of course)


rf_gateway_cc1101/433.92.rc.yaml

binary_sensor:
  ####### RC1
  - platform: remote_receiver
    receiver_id: receiver_433_92
    id: rc1_on
    name: "RC1 button ON"
    filters:
      delayed_off: 100ms
    on_press:
      - switch.turn_on: rc1
    raw:
      code:
        # prettier-ignore
        [+166,-500,...etc]
  - platform: remote_receiver
    receiver_id: receiver_433_92
    id: rc1_off
    name: "RC1 button OFF"
    filters:
      delayed_off: 100ms
    on_press:
      - switch.turn_off: rc1
    raw:
      code:
        # prettier-ignore
        [+166,-500,...etc]
  
switch:
  - platform: template
    name: RC1 - Switch
    id: rc1
    optimistic: true
    turn_on_action:
      - lambda: |-
          // here's the trick: swap to transmit mode only while doing it
          ((CC1101Transciver *)transciver_433_92)->beginTransmission();
      - remote_transmitter.transmit_raw:
          transmitter_id: transmitter_433_92
          code:
            # prettier-ignore
            [+166,-500,...etc]
          repeat:
            times: 10
            wait_time: 4.733ms
      - lambda: |-
           // and back to receive mode after sending
          ((CC1101Transciver *)transciver_433_92)->endTransmission();
    # turn_off_action: ... the same

The other two files:

  • 433.92.three-btn-white-switch.yaml
  • 433.92.door_sensor.yaml

are equivalent


rf_gateway_cc1101/custom_component.h

#ifndef CC1101TRANSCIVER_H
#define CC1101TRANSCIVER_H

#include <ELECHOUSE_CC1101_SRC_DRV.h>

int CC1101Transciver_module_number = 0;
class CC1101Transciver: public Component{
  int _SCK;
  int _MISO;
  int _MOSI;
  int _CSN;
  int _GDO0;
  float _bandwidth;
  float _freq;
  float _moduleNumber;
  void setup(){
    pinMode(_GDO0, INPUT);
    ELECHOUSE_cc1101.addSpiPin(_SCK, _MISO, _MOSI, _CSN, _moduleNumber);
    ELECHOUSE_cc1101.setModul(_moduleNumber); 
    ELECHOUSE_cc1101.Init(); 
    ELECHOUSE_cc1101.setRxBW(_bandwidth);
    ELECHOUSE_cc1101.setMHZ(_freq); 
    ELECHOUSE_cc1101.SetRx(); 
  }
public:
  CC1101Transciver(int SCK, int MISO, int MOSI, int CSN, int GDO0, float bandwidth, float freq) {
    _SCK = SCK;
    _MISO = MISO;
    _MOSI = MOSI;
    _CSN = CSN;
    _GDO0 = GDO0;
    _bandwidth = bandwidth;
    _freq = freq;
    _moduleNumber = CC1101Transciver_module_number++;
  }
  
  void beginTransmission(){
    ELECHOUSE_cc1101.setModul(_moduleNumber);
    ELECHOUSE_cc1101.SetTx();
    pinMode(_GDO0, OUTPUT);
    noInterrupts(); // workaround for https://github.com/esphome/issues/issues/2811
  }
  void endTransmission(){
    interrupts();
    pinMode(_GDO0, INPUT);
    ELECHOUSE_cc1101.setModul(_moduleNumber);
    ELECHOUSE_cc1101.SetRx();
    ELECHOUSE_cc1101.SetRx(); // yes, twice
  }  
};

#endif

Contribution

I'd love to make a self contained component, but I found no way to include the remote_transmitter and remote_receivers from within the custom component, so I ended up with this functional Frankenstransciver. If somebody knows how to do this and could assist me a bit, I'm more than willing to try to make an actual PR. I'm not aware of any other platform that can achieve this trickery.

@frma71
Copy link

frma71 commented Jan 8, 2022

@dbuezas Thanks for an excellent description. I've done the stuff above and it seems to be somewhat working. It's properly receiving and transmitting rf data. But, after I've done by first transmission reception stops working.

Any ideas ? What version of SmartRC-CC1101-Driver-Lib are you using ?

@dbuezas
Copy link

dbuezas commented Jan 8, 2022

Im using the version of the lib fetched by

libraries:
    - "SmartRC-CC1101-Driver-Lib"

If reception stops after a transmission, look at the last lambda after the transmission. I'd guess the chip is not set back to Rx mode,and the pin to input mode

@dbuezas
Copy link

dbuezas commented Jan 8, 2022

I've added an RSSI sensor component and I have the ambition of making a PR for a real component to avoid all this yaml hacks

@frma71
Copy link

frma71 commented Jan 8, 2022

@dbuezas Looking forward to it. I have the lambdas. Relevant parts of my configuration below:

custom_component:
  - lambda: |-
      // chip 1 (red) - RC
      // SCK, MISO, MOSI, CSN, GDO0, channel, bandwidth, freq
      // add DRate !!
      auto transciver_868 = new CC1101Transciver(2, 4, 17, 16, 15, 0, 158.03, 433.92);
      return {transciver_868};
    components:
      - id: transciver_868

remote_transmitter:
  - id: transmitter_rc
    pin: 15
    carrier_duty_percent: 100%

remote_receiver:
  - id: receiver_rc
    pin:
      # Don't use D3,D4,D8,TX, boot often fails.
      # Can't be D0 or GPIO17 b/c no interrupts
      # Can be D1,D2,D5,D6,D7,Rx
      number: 15
    dump:
      - rc_switch
    tolerance: 50%
    filter: 35us
    idle: 2ms
    buffer_size: 1kb

switch:
  - platform: template
    name: RF Outlet 1 On
    turn_on_action:
      - lambda: |-
          ((CC1101Transciver *)transciver_868)->beginTransmission();
      - remote_transmitter.transmit_rc_switch_raw:
          transmitter_id: transmitter_rc
          #                                                           SS
          code: '1101010010110010110011001010110010110011001101001101001010101010' #ON
          protocol:
            pulse_length: 250
            sync: [1, 5]
            zero: [1, 5]
            one:  [1, 1]
          repeat:
            times: 10
            wait_time: 4.733ms
      - lambda: |-
          ((CC1101Transciver *)transciver_868)->endTransmission();

@dbuezas
Copy link

dbuezas commented Jan 9, 2022

I see the following issues:

  • You call the component "transciver_868" but pass 434.92 as frequency
  • passed 0 as GDO0 but then use 15 as the pin for reception and transmission

@frma71
Copy link

frma71 commented Jan 9, 2022

@dbuezas I appreciate your help.

  • The name shouldn't matter ? Right ? My goal is to control 868MHz units, but since I had problems I took a step back to get it to work with 433.92 first.
  • I actually pass 15, the argument 0 (third from the end) is channel, which is a parameter i added to your custom_component.h.

Just to clear, reception works fine until I transmit the first time and transmit always works. So I doubt it's something trivial like that. I'm using the much faster esp32 so maybe there is some timing issue.

@dbuezas
Copy link

dbuezas commented Jan 10, 2022

Oh I see. I haven't tried it in an esp32 myself. The only test I can think of is to remove the interrupt disabling in begin/endTransmission.
This is there just to avoid getting the sent signal in the receiver, so if you send and receive the same codes, you'll need a boolean and a filter to disable reception temporarily.

@mortelil
Copy link

I've added an RSSI sensor component and I have the ambition of making a PR for a real component to avoid all this yaml hacks

Thanks a lot for working on this. How is the PR coming a long? I have a 868mhz CC1101 myself that I'm hoping to use to controll some lights in my house, but I'm way too intimidated by the yaml you posted to have tried it out yet. Hope to see this device integrated natively in ESPHome some day as a simple remote reciever/transmitter.

@dbuezas
Copy link

dbuezas commented Mar 31, 2022

sorry @mortelil I never got to it, not sure when I will. If you want I can post the 2 files directly in the meantime, it is not that much :)

@mortelil
Copy link

sorry @mortelil I never got to it, not sure when I will. If you want I can post the 2 files directly in the meantime, it is not that much :)

Yeah the 2 extra files would be great. I hope I can make sense of this stuff. Thanks in advance! :)

@dbuezas
Copy link

dbuezas commented Apr 1, 2022

@mortelil Here is the repo with the yaml file examples an custom component c file

https://github.com/dbuezas/esphome-cc1101

I'd recommend you to start with the basic one and then try the advanced one with an RSSI sensor and the ability to tweak the frequency and bandwidth on the fly to maximise reception/transmission distance.
have fun! :)

@mortelil
Copy link

mortelil commented Apr 6, 2022

@mortelil Here is the repo with the yaml file examples an custom component c file

https://github.com/dbuezas/esphome-cc1101

I'd recommend you to start with the basic one and then try the advanced one with an RSSI sensor and the ability to tweak the frequency and bandwidth on the fly to maximise reception/transmission distance. have fun! :)

Thanks a lot for the repo! The files were way easier to understand for a n00b like me. I was actually able to both receive and send raw data after a bit of trial and error. Now I just have to figure out why my stupid rf-lightswitch sends out different data for each press, and how to make the timing of the data I'm sending match the timing of the data coming from the switch. I'll make it work some day! Thanks again :)

@dbuezas
Copy link

dbuezas commented Apr 6, 2022

Try shortening the idle time to 2000us. Maybe you are getting multiple bursts in one

@mortelil
Copy link

mortelil commented Apr 8, 2022

@dbuezas I've been using Universal Radio Hacker and my RTL-SDR to look at the signal sent by my switch and by the CC1101. I figured out that the switch sent an FSK signal, so I read some SmartRC-CC1101 examples and added the line ELECHOUSE_cc1101.setModulation(0); to cc1101.h, which worked and made the signal match my switch more.
Here is my cc1101.yaml:

# https://github.com/dbuezas/esphome-cc1101
esphome:
  name: cc1101
  platform: ESP32
  board: esp32dev
  includes:
    - cc1101.h
  libraries:
    - SPI
    - "SmartRC-CC1101-Driver-Lib"

wifi:
  ssid: 
  password: 
  fast_connect: true
  power_save_mode: HIGH

logger:
api:
ota:

sensor:
  - platform: custom
    lambda: |-
      auto my_sensor = new CC1101(
        18, // SCK
        19, // MISO
        23, // MOSI
        5, // CSN
        22, // GDO0
        200, // bandwidth_in_khz
        868 // freq_in_mhz
      );
      App.register_component(my_sensor);
      return {my_sensor};
    sensors:
      id: transciver
      internal: true
remote_transmitter:
  - pin: GPIO22 # This is GDO0
    carrier_duty_percent: 100%

remote_receiver:
  - pin: # This is GDO0
      number: GPIO22
      # on the esp8266 use any of D1,D2,D5,D6,D7,Rx
      # Don't use D3,D4,D8,TX, boot often fails.
      # Can't be D0 or GPIO17 b/c no interrupts
    dump:
      - raw

button:
  - platform: template
    name: Garage
    on_press:
      - lambda: get_cc1101(transciver).beginTransmission();
      - remote_transmitter.transmit_raw:
          code: [-124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 373, -124, 124, -248, 124, -373, 124, -124, 124, -124, 248, -248, 124, -124, 124, -124, 124, -124, 248, -124, 124, -373, 124, -124, 622, -248, 622, -248, 124, -124, 373, -248, 248, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 373, -124, 124, -248, 124, -373, 124, -124, 124, -124, 248, -248, 124, -124, 124, -124, 124, -124, 248, -124, 124, -373, 124, -124, 622, -248, 622, -248, 124, -124, 373, -248, 248, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 373, -124, 124, -248, 124, -373, 124, -124, 124, -124, 248, -248, 124, -124, 124, -124, 124, -124, 248, -124, 124, -373, 124, -124, 622, -248, 622, -248, 124, -124, 373, -248, 248, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 373, -124, 124, -248, 124, -373, 124, -124, 124, -124, 248, -248, 124, -124, 124, -124, 124, -124, 248, -124, 124, -373, 124, -124, 622, -248, 622, -248, 124, -124, 373, -248, 248, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 124, -124, 373, -124, 124, -248, 124, -373, 124, -124, 124, -124, 248, -248, 124, -124, 124, -124, 124, -124, 248, -124, 124, -373, 124, -124, 622, -248, 622, -248, 124, -124, 373, -248, 248]
          repeat:
            times: 7
            wait_time: 99ms
      - lambda: get_cc1101(transciver).endTransmission();

It still doesn't work though, and looking at the analog signals in URH, there are two obvious differences.
I'm using repeat: in my yaml to repeat the signal. This makes the CC1101 just keep sending the "slow" signal during the wait between the repeats. See screenshot here (original on top, CC1101 on the bottom). My original switch stops sending data between the signal repeats.
Second problem: The wavelenghts of the slow signal doesn't match, see screenshot here. Any way I can decide the wavelenghts of the different parts of the signal?

@dbuezas
Copy link

dbuezas commented Apr 9, 2022

@mortelil
Let's continue in the repo to avoid spamming esphome :)
dbuezas/esphome-cc1101#1

@wiltet
Copy link

wiltet commented Jan 26, 2024

Hello @ALL,

unluckily I could not get my cc1101 board working (simple, cheap, green pcb 868MHz) on ESP8266 neither on ESP32 with @dbuezas solution.
Is there meanwhile a easyer, official integration in esphome for people with little knowledge about these things or got this project stucked at this level?

Ist there anybody special/known to be involved in this and be asked to maybe continue?

thanks for reading :)

@nullbyte-software
Copy link

+1 for support this in Esphome

@Redspray00
Copy link

I know I'm late to the game on this one but how can I get the DSC Security Contact Sensors I have to show up in my MQTT Broker? I've set things up as described above but I'm only receiving the Raw data not the decoded JSON like I do with my RTL-SDR.

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

No branches or pull requests