Reverse engineering remote Itho CVE ECO RFT – Part 6

Finally I’ve made a huge step forward in actually controlling the Itho ventilation box from my arduino, using a CC1150 RF-transmitter. This wouldn’t have been possible without Sander letting me swap my Itho remote control for his remote control, so thanks Sander!

If you are not interested in how I got this working, but want to see it working for yourself, head straight on over to my GitHub repository and download the code: Take a look at the AllFourButtons example. If you have a CC1150 RF transmitter, an Arduino Pro Mini (running at 3.3V) and 4 tactile switches, you can control an Itho RFT ventilation box by wiring up the compents like this:

Itho 4 buttons schema
Itho 4 buttons breadboard

In retrospect I had to solve 3 problems to get the code working:

  1. Know which fields contain the identity of the remote control (so I can re-create that number or create a fake number)
  2. Find out what the last 2 bytes in the first part of the message mean
  3. Find out what the 2 sets of bytes mean in the second part of the message that keep on changing every button press

The first problem (I thought) I had, was not knowing which bytes in the message actually contain the remotes unique identifier. My theory was that I had to generate another identifier for my Arduino based remote, or else the original remote would not work anymore. In the end it turns out both remotes work just fine when used interchangeable, but I didn’t know that up front. So I asked my colleague Sander if I could borrow his remote. That way I could analyze the messages being sent from his remote and analyze the differences. For each button press the Itho remote sents out 6 short RF messages. The first and second message are unique, the 4 messages after that are only repeats of the first 2. The first message contains 20 bytes in total, 6 bytes where different between the first and second remote. The second message contains 51 bytes in total, 5 bytes where different between the first and second remote. These were the only bytes that changed between the 2 remote controls, but stayed the same between 2 button presses on the same remote. I’m assuming the Itho ventilation box remembers these numbers when you preform the “join” operation when the ventilation box is turned on for the first time. Anyone using my code should perform a join first (untested yet!) with the identifiers in my code, before an Itho ventilation box will accept commands from the Arduino.

When I was analyzing the first message being sent for each button press, I noticed that the last 2 bytes only use a limited number of values. After looking at all the traces I had recorded I concluded that the last 2 bytes specify the previous command sent by the controller. So if the previous command was “go to low speed” and the command being sent now was “go to full speed”, the last two bytes of the first message would always be 85 and 77 (low speed). Each button/command has it’s own unique combination for these 2 bytes.

The second message that is being sent when a button is pressed, contains 51 bytes of data. This message contains 6 bytes that change every time you press a button (even if you keep pressing the same button over and over again). The only explanation I could think of, was that these bytes had to form a number that gets incremented with each button press. To find out what logic is being used to generate these numbers I put the 6 changing numbers in their own excelsheet and started searching for patterns and applying formulas. After a lot of searching I discovered that the 6 bytes formed 2 numbers, one that decrementes every button press and one that increments/decrementes based on the button that is being pressed and the previous button that was pressed before it. For example, if the Itho is running at low speed (was the last button pressed), and counter 1 currently has the value 100 and counter 2 has the value 200:

Itho current speed low low high high timer
Button pressed high high timer medium
Message 1 last 2 bytes 85, 77 85, 53 85, 53 85, 85
Message 2 counter 1 100 99 98 97 96
Message 2 counter 2 200 203 (+3) 204 (+1) 210 (+6) 206 (-4)

The counters in message 2 are not simply stored in two bytes, but are split across the bits of 3 bytes. The assumption I made in my excelsheets, to convert the binary bits back to bytes, actually made it harder for me to see these number. For example, if bytes 26, 27 and 28 of the first message contain the values 150, 150 and 166, then the number we are looking for is 99. How did I calculate this number? First you convert the byte values to bits, so 150 becomes: 10010110 and 166 becomes: 10100110. If you put all 3 binary numbers after each other you get 10010110 10010110 10100110. Now take the 10th bit (from the left), the 8th bit, the 6th, 4th, 2nd, 18th, 16th, 14th and 12th. If you put these bits after each other, you get: 001100011. If you convert this binary number back to decimal, you get 99. The fun part for this counter is, that besides the number 99 the Itho remote always sends another number along with this counter. To calculate the value of the other number you substract the value of the counter (99) from 511, so the second number would be 511 - 99 = 412. The second counter in message 2 uses the same kind of formula, only the first bit of the counter does not start at the 10th bit, but at the 14th bit.

So my current understanding of the protocol the Itho remote uses to communicate with the ventilationbox is as follows:

Message 1:

Byte start Byte end Default value Description
1 3 170 Start of the message (10101010 x 3)
4 6 173,51,83 header
7 9 id of the remote
10 10 id (7 bits) + command (1 bit)
11 13 The command
14 14 command (7 bits) + checksum (1 bit)
15 16 checksum (command specific)
17 17 170 footer
18 18 171 footer
19 19 Fixed value for the previous command: register = 77, unregister = 82, low/medium/full/timer = 85.
20 20 Fixed value for the previous command: register = 77, unregister = 171, low = 77, medium = 75, full = 53, timer = 85.

Message 2:

Byte start Byte end Default value Description
1 7 170 Start of the message (10101010 x 7)
8 16 171,254,0,179,42,171,42,149,154 header
17 24 id of the remote
25 26 counter 1
27 27 counter 1 (2 bits) + command (6 bits)
28 41 command
42 42 command (4 bits) + counter 2 (4 bits)
43 43 counter 2
44 44 counter 2 (6 bits) + footer (2 bits)
45 50 footer command specific: for join command (2, 165, 169, 169, 154, 86, 85, 5) for all other commands (2, 172, 170, 170, 170, 170, 170, 7)
51 51 footer (3 bits)

For my needs, the above code works perfectly. I do have a few future tasks and ideas:

  1. Convert the code to be commandable via the serial port and change the schema to work safely on a Arduino Nano (that can easily be hooked up to an Cubietruck or Raspberry Pi)
  2. Test the join and leave commands so others can use my code without knowing their own remotes unique identifier
  3. Get this code working with an CC1101, so I can also listen/receive the buttons presses from the regular remote
  4. Duration test
  5. Compare my findings with the results Klusjesman (a commenter on this blog) sent me.

If you are going to use my Itho (CC1150) code, please drop me a line in the comments below. I would love to hear your experiences and ideas!

Other posts in this serie: Part 1Part 2, Part 3, Part 4, Part 5

128 replies on “Reverse engineering remote Itho CVE ECO RFT – Part 6”

  1. Klusjesman

    Hi Rogier,

    You have made some nice progress and unraveled interesting details. Unfortunately I don’t have much time to play with my project because of work abroad. Also some parts are still traveling somewhere around the world. So no progress for me at the moment. I will keep you informed.

    Gr, Patrick

  2. HansB

    Hi Rogier,

    Thanks for your very interesting blog! I would love to experiment with the components & software you provide, but cannot find an 868 MHz CC1150 module, only an 433 MHz one (which, from the photo, looks exactly like the one on your blog). Do you have any suggestions? Is the 433 MHz module easily reconfiguarble to 868 MHz?

    Thanks & best regards,


    1. Rogier Reedijk reply to HansB

      Hi Hans,

      I’ve quickly searched eBay and AliExpress for a CC1150 at 868MHz, but could not find any. I’ve read the datasheet thoroughly and there is a difference between the 868 MHz and the 433 MHz boards, the difference is in the resistors between the CC1150 and the antenna. As I see it, you have a couple of options: 1) use the CC1150 433 MHz board and just try it. 2) use a CC1101 868 MHz board and adjust my code. You can buy this board on eBay, for example: 3) try to approach a Chinese seller that sells the CC1150 433 MHz boards and ask if they also have the 868 MHz boards

      I can’t look at your budget, but I would try options 1 and 2 in parallel. Order both boards and see which arrives first. Worst case for option 1 is that the fan won’t respond because the signal does not get through. Option 2 entails looking up the register differences between the CC1150 and the CC1101. Since both chips share the same datasheet this should not be too hard. The only difference between the CC1150 and the CC1101 is that the CC1101 also has the abillity to listen to RF, the CC1150 is send-only.

      Option 2 has been on my todo-list for a while. I haven’t gotten around to it, because I’m in the process of moving to a different house. So sadly I currently have no time to tinker with electronics.

      Let me know which option you choose and if you have any questions, just ask! I will try to help you any way I can.

    2. Klusjesman reply to HansB

      The one I bought also looks exactly like the image and is 868 MHz. I bought it on ebay i think, or aliexpress. w-tx1150 is written on the small board. I just checked it but I am not able to find the same component on the sites i mentioned earlier.

      Some while ago I played with the cc1150. I was able to communicate with it and set the frequency and do a read out etc. So my 3v-5.5v conversion with some mosfets and resistors were also working nicely. When I wanted to start sending messages to the ventilation unit I ran into some strange atmega problems (reset). Turned out I didn;t have enough memory on board, so I bought some other atmega’s. But since then I didn;t touch the configuration anymore. I’m just to busy with my company. So I guess this will be a long term project for me.

      I will order some CC1101, just in case I find some time to play.

  3. Jimmy

    On ebay I found, and ordered, this module: The title says 433Mz, but the description has “Operating in the 315/433/868/915 MHz ISM/SRD bands”. Would this module work? My coding and electronics skills are not very good. If I try and it does not work, would leave me with the question if it’s the module or something I did wrong.
    (buying a 1101 would also be a possibility but I really don’t understand what I would have to change for that)

    1. Rogier Reedijk reply to Jimmy

      Hoi Jimmy, I haven’t tried a 433MHz module myself, so I cannot definitely comfirm if it will work or not. My best guess is that it won’t work, or maybe with a very reduced range. The contradicting specs that you’ve read are that the CC1150 chips supports all frequencies, but the design of board determines which filters are used between the chip and the antenna. If you open the data sheet for the CC1150, you can find a reference design for a 433 and one for a 866 MHz board. Judging from the photo and the title of article that you found, this is actually the 433 MHz version. That means the filters on this board will most likely cancel out most of the 866 MHz transmission that you want to sent to the Itho. If you don’t want to much trouble, try to get a 866MHz board.

  4. Jimmy

    Hoi Rogier, thanks, yes I discovered how it “works” in the datasheet. It doesn’t seem to be changeable easy. Do you know if somebody has used the 868MHz version of the 1101? Because I can’t find a 1105 at 868MHz but I can find the 1101 at 868MHz (will take another 3 weeks on ebay). People above spoke about it but nobody shared his experiences afterwards.

  5. Marcel

    Hoi, interesting blog! I also searched for the CC1150 on 868MHz but couldn’t find it so I ordered a 1101. You started with the 1101, do you still have the code and could you share it?

    1. Rogier Reedijk reply to Marcel

      Hi Marcel, I’ve searched my development machine, but can’t seem to find the old (CC1101) versions of my code. I should have started using GitHub straight away… In my previous posts there are a few links to the CC1101 libraries I used. Maybe they are useful for you as well? Most of the code should be the same, since the CC1101 and CC1150 share a lot of registers. The only big difference between the CC1101 and CC1150 is that the CC1101 is also a receiver, because of that you will need to make a few extra calls to switch to transmit mode (which the CC1150 defaults to straight away). I would love to experiment with the CC1101 my self, but I recently moved and all my parts are still in moving-boxes. I also don’t have an Itho ventilation unit in my new house YET, so it’s probably going to be a few more months before I’m up and running again. If you have written any code in the mean time, please let me know. I would love to take a look and help you out in any way I can.

      Regards, Rogier.

  6. Erwin

    Hi Rogier,

    I got exactly the same module by the looks of it ( ), chip has 1150 number on it but sadly no luck on a working thing. I can send a join command but the Itho does not respond.

    Have you had any chance on further exploring this thing, maybe make some code to ‘listen’ with the cc1150 to the current remote control or something like that ?

    Great work so far !

    1. Rogier Reedijk reply to Erwin

      Hey Erwin, Listening to the current remote and extracting the id is a task that is high up on my wishlist/todo-list. Sadly, this won’t be possible with the CC1150, since this is a transmit-only chip. If you want to listen/receive you need the CC1101 chip. The link you sent is to a 1150 chip with a filter set for the 433 MHz band. So that might just be a very reasonable explanation why your Itho isn’t responding to the join command you sent (the Itho is only using the 868 MHz band). Just to double check, are you removing the power from the ventilation-unit and sending the signal during the first two minutes after you restore power? Because that is the only moment the Itho ventilation-unit will allow new remotes to join. Since my last blogpost I moved to another house and sadly the new house doesn’t contain a Itho ventilation unit YET. In the next few months I will most likely install an Itho unit and start working on this project again. In the mean time I will search for a CC1101 chipset on 868 MHz and link it in on this blog, because a lot of people are asking trying to recreate my setup and want to use my code. In the mean time, if you have any progress with you setup, please let me know!

    2. Jimmy reply to Erwin

      Same problem here with the ebay cc1150, it looks like sending join (and the other codes when pressing the buttons), but the itho does not respond. I know I have a 433MHz version, just like ERWIN, but that’s only a difference in the antanna filters (making transmission range on 868MHz bad). When I hold the cc1150 right next to the itho it still does not work.

  7. Peter

    Hi all, Thanks for the great info. i am planning on this as well, ordered the cc1101 see howit works out. I do have one remark for Jimmy, though it might have been obvious: the itho unit wanted me to active the remote after installation by pressing two diagonal buttons I think. I would say, after building, you need to do this as well. Could that be the reason for the unit not responding to the commands?

    1. Jimmy reply to Peter

      Hi Peter, because it dowsn’t work to press two buttons on the arduino, there is a special function called itho.joinItho(); which is called at startup, during setup(). joinitho() should send the same code as when you press 2 buttons on the original remote (except offcourse as being a different remote).

  8. Jimmy

    Today a few other tests and results. I have setup a tx/tx test between my 433MHz version cc1150 (tx) and 868MHz cc1101 (rx). This code helped me: (modified to use 868MHz) It is possible to send/receive at a short distance of a few meters with no antenna on the cc1150 and a a antenna on the cc1101. After searching, I also found that the antenna delivered with the cc1101 is not for 868MHz but 433MHz:

    I have now cut this antenna in 2 pieces, so I have a better antenna on the cc1101 and the cutted piece is just enough for an antenna on the cc1150. As to be expected with the 433MHz filters on my cc1150 board, range is still limited to a few meters.

    But at least I proved that it is possible to send data on 868MHz wih the cc1150/433MHz module. As I said in previous comments, I held the cc1150 module against the itho fan module, so that must be good enough.

    This only proved that my modules work with simple code, but still not sure if the itho code really sends and if so: what it sends.

    1. Rogier Reedijk reply to Jimmy

      Hi Jimmy,

      Thanks for all your feedback until now! It is really motivating me to look at my code again.

      I’ve also found and used the same code you found. Sadly that code will not work with the Itho, because of 2 reasons: 1) the code uses the packet mode, instead of the serial-communication mode for the CC1101 and CC1150 2) each packet is surrounded by preamble and a sync-word. This is extra data that the Itho ventilation-unit isn’t expecting.

      If you read chapter 27 “Asynchronous and Synchronous Serial Operation” of the CC1101 datasheet, the different serail modes are explained. Within my code I’m using the Synchronous Serial Operation with all the extra features DISABLED. That is the only way the Itho ventilationbox will accept data.

      I’m currently doing some research how hard it is going to be to implement a receive method that scans for the remote-id. I think I will be able to write one, but it’s going to be even harder to test this method, since I currently don’t have an Itho remote control. So I’m probably going to do the same setup you created (an CC1150 transmitting Itho codes, and a CC1101 receiving/listing for the remote id). I’ve I make any progress I will write a new blogpost or add it to the comments (and share my code on GitHub).

  9. Jimmy

    Here’s my latest “news”. Until now I was using a 5V Arduino and 5V/3.3V level shifters. Because I was not completely sure that I had never made any 5V/3.3V mistake, I ordered a new 3.3V Arduino Pro and a new CC1101 module. These are powered from my USB-FTDI Serial module which is also set to 3.3V. I checked Vcc, which is roughly 3.3V. But sadly the itho still does not respond to the join() function.

    But at least I now have a CC1101 with an Arduino Pro at 3.3V and a CC1101 with a ‘normal’ Arduino and level shifters. Those 2 sets could be helpful if anyone manages to create some listening/receiving code.

    1. Rogier Reedijk reply to Jimmy

      Hi Jimmy,

      Just a short update, I’ve actually started working on the receiving code. But I haven’t had enough time to finish the code, let alone test the code. I’ve been very busy lately, so haven’t had as much time for this hobby as I would like. I’m curious which CC1101 boards you actually have ordered? Do you have a link for me? The board I recently ordered arrived, but has half plated holes and not the regular 0.1inch spacing between the holes, so connecting this board to a breadboard is going to be difficult (at least with my current soldering skills).

      As soon as I’ve had some more time to work on the code, I will let you know.

      Regards, Rogier.

  10. Ed van Rijn

    Hello Rogier,

    This is a very interesting project. I recently replaced my old ventilation unit by an Itho unit also and decided that i wanted to add my own controller with some special functionality to control it as an add-on for the 2 remotes i have. Without your project I might not have started because the protocol for the unit is not available but with your code i should be able to get my own controller working. As everybody found out already 868 MHz transmitters are not available, you could use a 433 MHz board but then you will have to replace the inductors and capaciitors for the antenna circuit because the 433 MHz version will lower the output signal so much that the range will be very small (if it works) . So i decided to make my own pcb based upon the demo boards of Texas Instruments. I work as a hardware designer and i could import the Texas Instruments designs without a problem, then i added my own processor and some other stuff i will need in the future. The board design is in production now and i will receive the finished pcb’s next week. I will order the parts also so i hope i can start assembling the boards soon and start with writing firmware when the processor part is running. I posted the schematics and a picture of the pcb on github :

    I will let you know how it goes

    regards, Ed van Rijn

    1. Rogier Reedijk reply to Ed van Rijn

      Hi Ed,

      Thanks for sharing the pcb! I’m very curious what your project will be doing besides controlling the Itho, because I see you added a microphone input? My future goal is to make my own pcb as well. I didn’t think about using the reference design from Texas Instruments, that’s a very good tip! The only thing stopping me from spinning up my own pcb right now is that all components are smd components. How are you going to mount the components when you get the boards? In the past I did some research on a reflow hot plate, but never got around to actually buying one.

      Please do keep us posted on the progress you make. I will be following your GitHub repo. If you have any questions, feel free to ask here or sent me an email at rogier(dot)reedijk(at)gmail(dot)com.

  11. Klusjesman

    I am working on some code for the CC1101 to be able to send and receive data. I have a few 868 prints. According the CC1101 datasheet a clock signal of 26MHz is required for the 868 range. The Itho print contains a 26MHz crystal. The only thing I don’t know is where the ATMega169pv is getting its clock signal from since the max supported clock is 20MHz. Currently I am running at 14.7MHz. I will order some 26MHz crystals.

    1. Klusjesman reply to Klusjesman

      I just ordered some crystals and did a discovery afterwards. The 26MHz crystal is on board of the 868 print.

  12. Jimmy

    It took some time, but now I have an RTL-SDR. What I see is that the original RFT transmitter does a transmission at 868.something MHz. I see thee short transmissions. With the arduino/cc11xx, when I keep the antannas very close to each other, I only see 3 slight shifts in the noise over all the bandwidth. When I “tune” to a totally different frequency (like 433MHz), I still see such a slight noise change. What I suspect is that the cc11xx does transmit something 3 times, but at a totally wrong frequency. Because I don’t know how to figure out where or what it transmits, it still stucks me here. (I am using an RTL-SDR stick with the R820T2 chip and the SDRSharp software)

    1. Jimmy reply to Jimmy

      With a bit of shame I must confess that I have now returned to the original library files and now I do see TX from the Arduino/cc1101 at 868.x MHz. Probably next thing is to find out if it is possible to determine why the itho does not respond by doing something with what I can receive/capture? We may need to compare the original rtf tx with the arduino tx. Anyone has experience with handling the data that I can see now? From SDRSharp or rtl_sdr.exe I can extract a WAV (or I/Q) file.

      It could be just a calibration-issue with the rtl-sdr or the software, but I noticed that the RFT and cc1101 transmissions are at about 868.284671MHz, instead of 868.299865MHz. They are both at (nearly) the same frequency, that won’t be any problem.

      Comparing the captured waves, I do see big simmilarities and small differences in the structure. 3 sessions, each consisting of 2 parts. The first part on the RFT is 0.038mS, on the CC1101 about 0.034mS. (may be measuring tollerance) The 3 session together on the FRT 0.237mS, on the CC1101 only 0.188mS. Looks like a difference. The first and second part seem to have a different encoding, but they are the same kind of encoding on RFT and CC1101. The waves from the RFT are very clear, from the CC1101 they are somewhat distorted. All above does not really look like the reason, it’s only details.

      If anyone is interested, I can post the 2 files somewhere. A simple wavetool like Audacity helped me looking at this detail. (thanks to the guy from the earlier mentioned Zigbee me Decoding itho RF Protocol blog, who pointed at that tool)

      I think I can see/recognise the bits as ones and zeroes in the waveforms. But it is (nearly) impossible to compare all bits by hand. :( Anyone know some tool for that?

  13. Jimmy

    Via my approach, receiving with the RTL-SDR, I have managed to read about all bits and bytes from both the original RFT and the Arduino/cc1101 now. I have been able to get the ID from my RFT and changed the Arduino code to use that same ID. When I then compare both, they do have the same bits and bytes. But still the itho fan does not respond to the arduino. So I searched for other differences.

    For now I only focus on the “low” command.

    1) As to be expected, there are differences at the points of the counters. For instance: Halfway the const byte itho_RFT_message, the code reads: 154, 86, //fixed value 0, 0, 0, // counter + commands Some hard to follow function setCounter1Bytes shuffles bits in 0,0,0. My RFT sends 85, 166, 102. The arduino sent 85, 153, 102. But because these are part of a Counter, I think it is logical that they differ?

    Another Counter: The code says: const byte itho_RFT_low_command[] = { 38, 89, 150, 170, 165, 101, 90, 150, 85, 149, 101, 89, 150, 85, 150, 6}; Then the code shuffles the last byte (6): // correct the bit position of the last command byte result[41] <<= 4; Then it adds a counter that shuffles that byte again: setCounter2Bytes(counter2, &result[41], &result[42], &result[43]); And then the footer is added: const byte itho_RFT_regular_footer[] = { 2, 172, 170, 170, 170, 170, 170, 7}; The RFT differs here in 3 bytes, starting from result[41], which I think is also because of the counters.

    Then I discovered that my RFT sends a different itho_RF_low_command, so I changed it: const byte itho_RF_low_command[] = { 1, 84, 213, 85, 83, 51, 84}; // Last 2 bytes from my RFT are different

    So looking after fixing the itho_RF_low_command, the only difference between the RFT and the Arduino is around the counters. Because it still does not work, I’m afraid it has to do with the counters, that are not “in sync” between the RFT and the Arduino. Am I possibly right?

    1. Klusjesman reply to Jimmy

      I think they are doing some trick with those counters. The remote and the receiver cannot be completely in sync in my opinion. Suppose you walk outside your home and press the remote a couple of times. When you return close to the receive and use the remote it still works. This should not be possible when the remote and receiver are completely synchronized using those counters. Because of the missing messages you would expect the remote to be out of sync.

      It is nice the RTL-SDR is working. How does it handle the noise?

      For me things are getting clear about the structure of the two RF messages. Since Itho is not using hardware packet handling the Atmega needs to track the packets itself. This is why the 170 values come into play. It is used to detect the beginning of the message and synchronize the timing to be able to peek at the next bits. Also I am starting to understand why async mode is used at the receiver side. With sync mode it is really difficult to receive only the first 32 bits without noise. During async receive the bits are high/low for times between 20us to 30us. This is why the bitshifts for the counters are required. With a long sequence of 0 or 1 it will be difficult to detect how many 0’s or 1’s there are. The max sequence for bits with the same value seems to be 2 bits. So the time between a rising and falling edge is always between 20 and 60us (there is one exception in the second message, but it is a fixed sequence).

      The noise becomes clear when looking at message 1 in Salea analyzer. There are 8 clock pulses for 1 bit (because of the datarate difference between the two messages), But in the analyzer tool I do not see nice blocks of 8 bits. So using 8 peeks at the bits it needs to extract the intended meaning.

      I am wondering if the noise is caused for a big part by the cheap CC1101 print. However, with other (different) cheap print the results are the same.

    2. Rogier Reedijk reply to Jimmy

      Hey Jimmy!

      It is logical that the counters differ between the Arduino and the original Itho remote. My code just starts the counter at an arbitrary number and decreases the counter number on every message. As far as I’ve seen the Itho box isn’t expecting numbers to be a nice lineair set. The only restriction I’ve found is that sending the exact same message (with the same counter values) doesn’t seem to work.

      Looking back at my own code, I see that the low-command for both the remotes I tested with (ITHO_REMOTE1 and the ELSE block) are different. So I’m not really surprised that the low-command from your remote is also different. The question remains what those last 23 bytes mean. It could be yet another identifier for the remote… On the other hand, my remotes should actually work with your ventilation box (as long as the remote is joined). So as long as the message contains the values the Itho box is expecting, it shouldn’t matter which identifier the Arduino uses.

      It sound like you are very close to getting it working yourself! It sounds like there is just a very small difference in the message that you haven’t found yet. Keep up the good work and do let us know if you make any progress.

      As soon as I find the time I will continue working on my own receive code and upload it to GitHub. And then I should buy an actual Itho ventilation box so I can actually test my code again in my new house. ;-)

  14. Jimmy

    There’s not much noise and not much difference between the RFT and CC1101 signals. Sometime I seem to miss a bit (partial), but I think that is not because the RFT/CC1101 but because I have to use the RTL-SDR on the edge of speed. E.g. I need to use a sample rate of 3.2MSPS, while documentation says 2.56 is max for most environments.

    For now I am manually looking at the captured signal and finding the 1’s and 0’s. (which is difficult when sometimes losing a bit) So for me the 170’s are also very handy to see if I am still “reading in sync”. When placing multiple captured waves next to each other, it’s possible to find the differences. If I find such a difference I need to find the actual position in the bitstream compared to the Arduino code, to figure out what the real difference is. That way I found my own RFT ID. (which I need to double-check because it still doesn’t work)

    You are right that the counters cannot be too exact. On the other hand, those are the only difference I can find now. If I have more time to spend, I could try to capture and decode one packet from the RFT, try to recalculate the counters and send that from the Arduino/cc1101.

    I am now comparing my RFT low/mid/high/timer codes, to see what my RFT actually sends.

  15. Klusjesman

    I am finished with my code to parse the incoming messages, it is on github. At the same time I made functions which are doing the opposite for sending.

    I only have 1 counter in my code. It is a byte (0-255). It is just incremented on every button press. All 6 counter bytes are derived from this single counter. I have tested the code using a database containing thousands of RF message data and it all works fine.

    There are the following commands: - join, leave - low, medium, full - timer1, timer2, timer3 (when you press the timer button 3 times quickly it will send a message on every press = timer1, timer2 and timer3 command)

    The code contains a function to get the counter value out of the first 3 counter bytes in the message. And there are functions to generate the 6 bytes out of the counter value for sending.

    I guess the unknown bytes which are left are all for the device id.

    1. Klusjesman reply to Klusjesman

      I am able to control my ventilation using the CC1101 without any problems. The Itho remote and my own remote are working together at the same time, using the same id’s. At the moment my leave implementation does not work. Join and leave have different sized messages, also compared to the normal commands. I am using FIFO for sending and receiving and this is working fine. I did not test the join command yet. When the join and leave commands are working everybody should be able to control their Itho ventilation using my code.

      It is not possible to just put your own device id into my code because it will not work without making some changes to the calculations of the counter bytes.

    2. Klusjesman reply to Klusjesman

      The join and leave commands are also working properly now. So everybody should be able to join the atmega to an Itho Eco Fan RFT and have full control.

      The only thing I will spend some time on is to simplify the code and calculations for the counter. This will save some bytes from memory.

  16. Jimmy

    Since klusjesman was making great progress, I decided to follow his developments closer ad implement all his changes to Rogier’s code. I tested his findings on my itho/rft and we discovered many new things. For instance, with my RTL-SDR I saw that the join (and leave) command was much larger, and that the counters from klusjesman did not match the counters from my RFT. With those new findings and much of his research, Klusjesman got closer to a complete solution, so I completely switched over to his code. To use his code, I needed to change things to make is work with the Arduino IDE. (Especially SPI was different, so for a lot of SPI related functions I took parts from Rogier and other internet resources and put those into the code from Klusjesman)

    To make the code from Klusjesman compatible with my own RFT, I had to change some things as expected, like the Device ID and the ComandBytes. But then it turned out that there are also differences in the counter-bytes, like some parts are shifted and some bytes are just different or in a different order. I managed to fix those too, so at last my Arduino+CC1101 worked the same as my RFT module.

    Next step for me was to make it work on an ESP8266 module instead of an Arduino, which involved a slight SPI change and inserting a few “yield()” codes to prevent the ESP8266 watchdog to kick in.

    Today I took the last step important step, I took the RFT device ID, command-codes, and the counter-calculations from Klusjesman. After turning the Itho fan off/on, it accepted the Join command! So now we have proven that we can use his code without having to figure out one’s own device-id etcetera. (which might only become a problem if your neighbor also has an itho and starts to use this code…)

    1. JFdB reply to Jimmy

      Dear Jimmy, Can you post the changes that you made to the code of Klusjesman? I downloaded his code, and I have great difficulty to incorporate the assembler code (the .S file). The arduino compiler is complaining a lot about this file. And I have not even encountered the SPI problems that you mention above, so I do not know what awaits me.

  17. JFdB

    Dear Klusjesman, After checking with Rogier’s description I can see that the “wrong” message bytes (nearly) all relate to the device ID or the checksum. I understand I can remove these print statements and all will work fine, but now that I have come this far I would like to understand it better (until I get bored and I just want it to work) What was not clear to me is what happens if I change the device ID in your code, will the calculation of checksum and other bytes become incorrect? Does your code only work with the hard coded device ID? (I think so but I am not sure)

    I understand I can extract my device ID from the message dump provided by your program, but can I reconstruct the full message needed for this device ID (i.e., is there a sound algorithm to do this), or do I need to solve my own puzzle (pressing all the buttons and recording the messages) like you and Rogier apparently did.

    In my previous post I could not print the angled brackets in the following statement:

    “except for the BBuart library, that was included with #include (angled bracket open) BBuart.h (angled bracket close) (note the angled brackets instead of the quotes)”

    1. Klusjesman reply to JFdB

      A few bytes will be incorrect when you are gonna use your own device id. Jimmy did some work on this already for his remote. You will need to press buttons to find out the relation between the counter bytes. I believe the only changes are related with the starting offset within the arrays. But it should not be that hard since you have a nice log of all bytes ;), It is a lot of work since one cycle of the counter is 256 button presses. Also you have to be careful with the button. After thousands of button presses it ruins the buttons. Especially when you want to test button combinations.

      I am busy with work the next months so I am not working on it anymore. For me the code is good enough, for now. It works and there is a possibility we never find a algorithm which works for all device id’s. There could be a chance the counter, device id or some other variable which influences the calculation is stored in EEPROM on the remote.

  18. Rogier Reedijk

    JFDB, I’ve juist trad through the datasheet and on page 56, chapter 20 called “Data FIFO”, there is a table that specifies when a buffer under flow will occur. You are right that it’s related to the message being bigger than 64 bytes. Looking at the code Klusjesman has written, the initSendMessage2 method should be changed, because it sets the PKT_LENGTH to an invalid value (cannot be higher than 64 bytes). Also in the SendData method there should be a register write that sets the FIFO_THR to the remain bytes (most likely 72 - 64 = 8) to prevent the buffer under flow message. If I read the datasheet correctly, in the current implementation the last 8 bytes won’t be transferred because of the buffer under flow (ea the buffer isn’t filled to the fixed packet length value, and thus cannot start transmitting).

    Sadly I still haven’t had the time to test out the code Klusjesman wrote, but with these changes it should work. When I find the time I will try to update my GitHub repo and also submit a Pull Request to Klusjesman’s repo to address this problem. If anyone has more time to do this, feel free to post the necessary changes on this form or sent them to me or Klusjesman!

    1. Klusjesman reply to Rogier Reedijk

      The PKT_LEN is not the problem because packages bigger than 64 bytes are allowed. You just have to fill the FIFO with new bytes while it is transmitting. In the code I am putting new data in the buffer when there is free space for 2 bytes. Using the FIFO it is possible to send and receive really big messages.

      If speed is a concern then you probably need to use an interrupt on GDO as indicator when you can put more bytes in the FIFO. But since the code is working on my ATMega328P I did not spend time on this. Also the current implementation is way easier.

      I guess you moved to Arduino SPI and are using Arduino libs? First thing I would do is strip out the Arduino functions because they have extra overhead compared to using the ATMega registers directly.

      I remember Jimmy having similar problems in the beginning but I cannot remember what the exact cause was. I believe it was something related with the implementation of the writeBurst SPI function.

    2. JFdB reply to Rogier Reedijk

      Dear Rogier and Klusjesman, I figured out the problem. When the send message is larger than 64 (In klusjesman code actually 61) bytes, the send command routine first sends 61 bytes in burst mode and then starts checking the TX_BUFFER to see if the additional bytes can be send. However, due to a hardware bug, reading of some registers gives erroneous results, this was solved (as recommended by the CC1101 errata sheet) by reading the registers until two consecutive reads give the same results (readRegisterWithSyncProblem). However, this fails massively for a register that is continuously updated (like the number of bytes in the TX_BUFFER during sending). Thus readRegisterWithSyncProblem for the TX_BUFFER only returns when the buffer is empty, then two consequtive reads will give the same results. That is too late and leads to a TXFIFO_UNDERFLOW condition! The solution is to simply read the register just once, accepting that the value might be incorrect, but at least the TXFIFO_UNDERFLOW condition does not occur. Therefore the following statement:

      while ((txStatus = (readRegisterWithSyncProblem(CC1101_TXBYTES, CC1101_STATUS_REGISTER) & CC1101_BITS_RX_BYTES_IN_FIFO)) > (CC1101_DATA_LEN - 2))

      Was replaced by:

      while ((txStatus = (readRegister(CC1101_TXBYTES | CC1101_STATUS_REGISTER) & CC1101_BITS_RX_BYTES_IN_FIFO)) > (CC1101_DATA_LEN - 2));

      (Note the “|” in readRegister)

      Klusjesman: I believe this should also be fixed in your github post in the file CC1101.cpp

      I have successfully joined the Itho fan, and can control the speed from the arduino program. Success!!!

      I would like to post the arduino code on github, but I have never done that before. Can I fork from Klusjesman or Rogier your code? Klusjesman seems most appropriate, I have only made a few changes to his code. Both of you, again awesome job figuring out the Itho messages and writing the code to program the CC1101 module, thanks so much

  19. JFdB

    What I don not like about the fix is that it is not robust. I tried to think through the consequences of the txStatus = (readRegister(CC1101_TXBYTES | CC1101_STATUS_REGISTER) & CC1101_BITS_RX_BYTES_IN_FIFO reporting the wrong number of bytes in the TX_buffer. If it reports more bytes than there actually are -> no problem, on the next loop it will be most likely correct. If the number of bytes in the TX_buffer is reported smaller than it actually is, then the program thinks it can send more bytes into the buffer than there is actually space and data in the FIFO will be overwritten. I tried to create this situation to see what kind of error would be reported, but I could not write data fast enough into the buffer to create an overwrite. I was expecting that a TXFIFO_UNDERFLOW would be created, because due to the overwrite, less data is written to the buffer than needs to be send. This error could be caught by the program an handled to make the program robust.

    1. Klusjesman reply to JFdB

      I am running with a 14.7456MHz crystal. The SPI connection is set up at a low speed (SPI::Init). You can try to increase the SPI speed to see if it solves the problem.

      “What I don not like about the fix is that it is not robust.” It is not really related with the fix but with the way the send function is working for messages bigger than 64 bytes. The status is already retrieved so it would be easy to add some extra checks to check for overflow/underflow. There can also be a short timeout on the function.

  20. JFdB

    I decided not to play with the play with the SPI speed (otherwise it becomes hardware dependent). I implemented a readregister function that returns the median of 3 values. readRegisterMedian3 This should reduce significantly the probability that incorrect values are read from a register, and at the same time should be (somewhat) save for reading e.g., the TX_BUFFER register that is continuously updated. It should be tolerant to reading no more than one incorrect value out of three. Updated the sendData subroutine with this change, and added jumping out of the subroutine in case of a TXFIFO_UNDERFLOW. I put a pull request to Klusjesman. I created a repository for the Arduino code: :)

    1. JFdB reply to JFdB

      Dear Klusjesman, What still puzzles me is your BBuart.S file, specifically the port for serial communication. For the arduino project I had to make the following changes: In the BBuart.S file the port needed to be changed from PortC to PortD (serial port on the Pro Mini is on portD) The UART_TX needed to be changed from 0 to 1 The UART_RX needed to be changed from 1 to 0 The changed three lines in BBuart.S are below:

      #define UART_Port (PORTD-0x20) #define UART_Tx 1 #define UART_Rx 0

      We both use the ATMega328P chip, in the data sheet the USART is given as: PD1: TXD (USART Output Pin) PCINT17 (Pin Change Interrupt 17) PD0: RXD (USART Input Pin) PCINT16 (Pin Change Interrupt 16)

      Are you sure that define UART_Port (PORTC-0x20) is correct in your code, shouldn’t it be PORTD? I am happy to change it on github, but if you tested it with PORTC i will leave it alone.

  21. Jimmy

    Hi all, sorry for the silence. Before posting my Arduino (and ESP8266) code, I want to do a big clean-up. What I want to do is to create a fork of Klusjesman’s code and then put my modifications onto that (on my fork). But now I see that JFdeB is also making changes to klusjesman’s code and I am not sure if I want/need those in my Arduino/ESP8266 version.

    So @Klusjesman, can you confirm that you are confident with JFdeB’s changes, and should I take those into my code too?

    1. Klusjesman reply to Jimmy


      For my own project I will use my original readRegisterWithSyncProblem since this is what TI is recommending and is also working nicely on my Atmega. When the readRegisterWithSyncProblem function is giving problems it means you are running into the SPI sync bug a lot (=unreliable read result). I rather like solving the real problem instead of implementing a work around.

      I will only include the underflow check. But there are some other checks I will add (when I have time). There is one more bug in the CC1101 which needs to be addressed in the code. Also I will increase the SPI speed because it is running at the lowest speed. At least the speed can be doubled.

  22. André

    Why are you using seperate rf and controller boards? There are Jeelabs usb sticks available that are all in one!

    I have both types, the Classic and the V3c with RFM12b or RFM69CW 868MHz transceivers and an AT328 on board. These sticks are handy when using a Raspberry Pi or even a Windows pc. Is it possible for someone to port the code so that it can work with a Rpi? The only thing needed is serial comms with the usb port as far as I understand.

    1. Jimmy reply to André

      Hi André, an Arduino or ESP8266 together with a CC1101 cost about 7 euros (perhaps +3 euros, if the Arduino/ESP doesn’t have serial yet), while the jeelink costs 32,50 euro. Beside the price, how would you add things like a few buttons and a CO2 sensor to it?

      If you choose to use an RPi with a CC1101, it should be “relatively easy” to port the code, since rPI also supports SPI: AFAIK the RPi is also 3.3V which makes connecting the CC1101 to the RPi easy too. All you will have to do is write RPi code that does the same as the code from Rogier and Klusjesman…

      If you want to use a different radio-chip like that jeelink’s RFM69CW, you will need to figure out how to make that chip send the same bits with the same speed at the same frequency with the same modulation as we do now with the CC1101. Since it is ‘exactly known’ what is sent, you can to tell the chip to do the same.

      Why don’t you just buy your own Arduino+CC1101 for a few euros? :)

  23. JFdB

    Hi Rogier, I am very far along reverse engineering the ELRO alarm system HA68. I can read the messages from the door sensors, the smoke alarm, the entry keys and the motion sensors. Was quite some work figuring out the CC1101 settings to intercept the messages. Any interest in this info on maybe a separate project page?

    1. Rogier Reedijk reply to JFdB

      Hey JFDB,

      Sounds like a lot of work! Off course I’m interested in the code. But don’t you want to put the code on your own blog? (easily created for free at for instance) Or else create a project page on This way more people will find your project and code.

  24. Leon Arkesteijn

    Hi Jimmy,

    I started your code as recommended by JFdB.

    got all the parts, soldered it together and loader the program, so up and running. However I’m not so experienced in coding and now have a question. In the code of Rogier it works with 4 buttons, however in your code I do not see the buttons in the code. Is this with a reason, do I need to add this code myself or do I miss something?

    1. Jimmy reply to Leon Arkesteijn

      My code is not excluding buttons, you can just use any way you want to send any signal. If you want to use buttons, you can do something like in Rogier’s code. If you want the speed to be controlled by any sensor, you can use any code to read the sensor and send a command depending on the reading of the sensor.

      For example, you are using an analog CO2 sensor. When the sensor gives an analogRead value of 200 you want to send the Full. Then you can add code to your loop like: int a = analogRead(A0); if (a99) && (a200) sendFullSpeed();

      Just be creative.
      (and make sure you are not sending a command every time your loop() runs, otherwise it will send almost continously)

  25. JFdB

    Hi Leon, Jimmys github code is simple to understand. The setup loop tries to register the arduino device as a remote with the fan. The loop loop just monitors communication to the tho fan. If you want it to send a commend, just insert the code sendFullSpeed(); at the end of the loop() loop But since the arduino runs this loop multiple times per second, it is better to include a delay statement, like sendFullSpeed(); delay(100000); //this delays by 100 seconds All is functional when your fan speeds up to full speed when you run this code

    1. Leon Arkesteijn reply to JFdB

      Thanks (both) for your replies,

      I indeed got it working by adding some code. I tried to make this a “mysensor” node to easily integrate into my domoticz. but unfortunately I was not successful in having two SPI devices combined (CC1011 and NRF24L01). therefore I now use two arduino’s that communicate with some IO pin’s (not the most elegant way, but it works) However I wonder that the while loop does, you say it monitors the communication, but I thought the receiving part was not operational? or should that work as well. (the pins are not connected now I think?)

  26. Leon Arkesteijn


    quickly added some debug code, but nothing came in at all. My transmitter is about 6m distance in clear sight. I will look into this further when i have my new hardware in.

    1. Jimmy reply to Leon Arkesteijn

      Leon, did you double check the cabling? Like I said yesterday, there was a mistake in my previous descriptions… Also please do a test within a few cm range, just to be very sure it’s not an antenna problem.

    1. Jimmy reply to Leon Arkesteijn

      I don’t know what your exact code looks like, but I noticed in my current code that I need to call rf.initReceive() after a call to sendCommand(). So if you send a command, call initReceive again to be able to receive.

  27. Olivier

    Hi all, many thanks for the hard work! With Jimmy’s code and a few changes (#include for uint_8 and remove the #include ) I got the code working on a CC1101 and a wemos D1R2 (esp8266), and it worked like a charm! Going to link this to a DHT22 in order to automatically adjust the fan.

    1. Jimmy reply to Olivier

      Hi Olivier, can you wxplain what you mean/did with the #include and remove #include? Perhaps I can make the code more general to keep it working on generic esp and nodemcu while also compatible with wemos?

  28. Rick

    Nice article.

    Is it possible to get this work with a Aurel Tranceiver RTX MID 868 OOK?

    I am trying to get my Itho cve work with a RFLink.

    1. Rogier Reedijk reply to Rick

      Hi Rick,

      In theory you should be able to control the Itho with any 868MHz RF transmitter. So the Aurel transceiver could also work.

      The challenge however, will be to write the code to sent the correct data using the specific commands for the Aurel.

      The people on this blog that successfully controlled the Itho all used (nearly) the same chipset that Itho is using. This way it’s easier to send the exact same data.

      The code people have posted and used on my blog can help you decipher the protocol and maybe create an implementation for the Aurel. But it will definitely take you some time. So it’s not a easy as copying the code found on this site.

      If you do get it working, please let us know!

  29. Dobie

    Hi Guys, Thanks for the great Job you’ve done. I bought the hardware on Aliexpress for under 5€ and can control my fan via Internet now! What i am missing is a way to switch the fan off completly. I suspect the fan controller does have a command for that but it was obviously not discoverd till now. Does anyone have an Idea?