Adding IR send and receive capabilities to my home-assistant based smart home

Or, how to control your A/C from your phone

You may have seen my earlier post about my new home automation setup. Well I just upgraded it! I just finished testing out a new infrared remote control send and receive capability and it is pure awesome. Here’s what I can do now from within home-assistant:

  • Turn on and off my new DeLonghi portable air conditioner from Costco, and set the temperature to whatever
  • Turn on and off the TV and press any buttons from its remote control
  • Turn on and off the stereo and virtually press any buttons from its remote control (which I never even had!)
  • Use an old random blueray remote control to set scenes, turn lights on and off, etc. (basically do anything under home-assistant’s control)

This post is about how I did it on my Raspberry Pi.

Update: A video!

Annotated setup with IR sensors

Setting up LIRC and learning the A/C remote

LIRC is a linux library to interface with infrared (IR) remotes. Setting it up, including schematics for hooking the IR receiver and emitter to the GPIO ports of the Pi are well-described here. So following those instructions is the first step.

(2019 Update: See this info, as some raspberry pi internals related to LIRC have changed!)

Then I had to teach LIRC about my equipment. The one I was most worried about was my DeLonghi “Pinguino” portable air conditioning unit from Costco (AN125HPEK). I was able to successfully learn the commands from the remote using LIRC in raw-capture mode. This post was very useful in figuring it out. A/C units send full packets, including information about what mode it’s in, what numerical temperature it’s set to (not just up and down), etc. Here’s what I did:

  1. I recorded a bunch of raw data and remember the order of buttons you pressed. For example, first I had the remote at the maximum temperature and then after I started recording I pressed “decrease temperature” a bunch of times until I was at the minimum:

3. Then I used irrecord  in analyze mode to process the raw signals and extract the hex codes:

blew my mind when it worked. Yay. Excellent progress. I used irrecord in its normal learn mode to learn my Sony remote and it just asks you to name each key before you press it. That worked great. The codes I recorded for this A/C are available here.

My A/C
My A/C
My IR transmitter
My IR transmitter

Writing a new home-assistant component for lirc

With what I had up to this point, I could use home-assistant as is and use the shell_command component to control things around my house. This was what was recommended last time a lirc component was requested. I tried it out and it worked great:

But then I got thinking that it’d be cool if I could have a IR remote control various aspects in home-assistant. My wife sometimes complains that she has to go find a phone to turn on the lights. If I had a remote laying on the table it’d be really easy to select scenes and whatnot. So I thought I’d write a lirc component.

Conveniently, there’s a python-lirc package in pip that brings lirc capabilities into Python3. So making a component was just a matter of interfacing between that package and home-assistant. I whipped up a component and tested it out by having KEY_1 turn on a scene and KEY_0 turn all lights off. It works! SO AWESOME!

I will open a pull request and try to get this feature into home-assistant for all to enjoy.

My "new" home remote
My “new” home remote
Lirc remote in home-assistant
Lirc remote in home-assistant. UPDATE: I’ve since converted to a event-handler so it doesn’t show up like this

Now I can make rules that, you know, turn on my tv, my stereo, and put up a fireplace video like this:

So awesome. I have submitted the code as PR 2139 and maybe it will go in the next release.

I’ve started toying with the shell_command to allow it to build the command from slider input so I can set the A/C to any value I want. Will open another PR if this guys doesn’t.

44 thoughts on “Adding IR send and receive capabilities to my home-assistant based smart home”

  1. hi there
    i really like your post
    but also really needs your help in recording my A/C
    i followed the link but i couldn’t follow with all the comments
    can you please write your own one in details? like how to manage the raw file and when to stop holding the key on in my remote…
    thanks
    (can i write you an email?)

  2. Hey, nice! I’m not using LIRC and can’t manage getting the IR codes, could you please share the ones you recorded? Many Thanks!

      1. Right, I tried to c&p those into the eventghost usb-uirt transmit-ir plugin but it did not work. Not sure if its the wrong code (I own a pac-cn92) or if the codes would need to be converted.

        1. Don’t know if you need this anymore: You are right, the codes are completely different for this model. I recorded them, and here they are:

          begin remote

          name DELONGHI
          bits 32
          flags SPACE_ENC
          eps 30
          aeps 100

          header 9111 4465
          one 574 1626
          zero 574 525
          ptrail 581
          gap 183413
          toggle_bit_mask 0x0

          begin codes
          AC_16 0x12181100
          AC_17 0x12181180
          AC_18 0x12181140
          AC_19 0x121811C0
          AC_20 0x12181120
          AC_21 0x121811A0
          AC_22 0x12181160
          AC_23 0x121811E0
          AC_24 0x12181110
          AC_25 0x12181190
          AC_26 0x12181150
          AC_27 0x121811D0
          AC_28 0x12181130
          AC_29 0x121811B0
          AC_30 0x12181170
          AC_31 0x121811F0
          AC_32 0x12181108
          MODE_SILENT 0x12481108
          MODE_MED 0x12281108
          MODE_MAX 0x12181108
          MODE_DEHUMIDIFY 0x12421150
          MODE_FAN 0x12111150
          TEMPERATURE_FAHRENHEIT 0x121817F2
          TEMPERATURE_CELCIUS 0x12181350
          TIMER_ON 0x12181350
          TIMER_OFF 0x12181150
          TIMER_1 0x12188350
          TIMER_2 0x12184350
          TIMER_3 0x1218C350
          TIMER_4 0x12182350
          TIMER_5 0x1218A350
          TIMER_6 0x12186350
          TIMER_7 0x1218E350
          TIMER_8 0x12181350
          TIMER_9 0x12189350
          TIMER_10 0x12185350
          TIMER_11 0x1218D350
          TIMER_12 0x12183350
          TIMER_13 0x1218B350
          TIMER_14 0x12187350
          TIMER_15 0x1218F350
          TIMER_16 0x12180B50
          TIMER_17 0x12188B50
          TIMER_18 0x12184B50
          TIMER_19 0x1218CB50
          TIMER_20 0x12182B50
          TIMER_21 0x1218AB50
          TIMER_22 0x12186B50
          TIMER_23 0x1218EB50
          TIMER_24 0x12181B50
          end codes

          end remote

          Some codes seem to be the same and I suspect that actually the codes do not represent a press on a certain button at all but rather contain information about all states of operation (mode, temperature etc.)

  3. Sorry for my lack of knowledge in H.A… but how did you get your scene “Bright” to display as an icon?

    1. No worries. Actually I don’t have that anymore. A few versions ago hass changed scenes so they’re not badges at the top anymore. I don’t think it’s possible anymore.

  4. Any suggestions on finding the gap? I tired using irrecord in raw mode, but I can’t get more than 2 dots to show up. I am trying to figure out the codes for my SPT portable AC unit.

    1. I couldn’t get anything useful out of irrecord directly either. I had to switch over to the mode2 command and then post-process the results with irrecord -a.

      1. This is my result from mode2

        4426 4410 569 1627 561 541
        563 1637 562 1637 563 539
        565 537 567 1630 568 537
        568 537 568 1632 571 532
        568 535 569 1626 563 1635
        564 539 565 1637 567 538
        562 1634 565 1632 566 1631
        568 1629 575 528 562 1639
        570 1629 570 1633 565 538
        567 535 589 519 586 512
        593 1604 594 509 595 509
        596 1607 592 1609 590 1602
        567 535 599 505 590 512
        592 511 594 510 594 511
        594 513 591 518 586 1604
        596 1600 568 1632 567 1628
        562 1635 563 5267 4492 4366
        567 1628 569 532 592 1609
        588 1607 562 541 593 510
        595 1602 597 508 596 509
        595 1606 593 509 596 507
        597 1600 589 1607 592 511
        593 1610 589 516 588 1609
        590 1606 593 1605 564 1632
        567 536 598 1602 597 1602
        597 1606 563 539 595 508
        596 506 589 514 590 1606
        593 509 596 509 600 1601
        594 1603 595 1601 598 504
        590 513 592 510 599 504
        595 509 596 508 596 507
        588 515 589 1611 598 1598
        596 1600 594 1602 597 1601
        567

        But this is the result when trying to use irrecord -a

        irrecord: decoding of OFF failed
        #
        # this config file was automatically generated
        # using lirc-0.9.0-pre1(emulation) on Fri Sep 2 22:30:51 2016
        #
        # contributed by
        #
        # brand: SPT
        # model no. of remote control:
        # devices being controlled by this remote:
        #

        begin remote

        name SPT
        bits 98
        flags SPACE_ENC|CONST_LENGTH
        eps 30
        aeps 100

        header 4448 4414
        one 579 1620
        zero 579 523
        ptrail 565
        gap 548544
        toggle_bit_mask 0x0

        begin codes
        end codes

        end remote

        1. Ok I’m onto something here. I took your raw codes and hand-split them into this file:

          begin remote

          name MYREMOTE
          flags RAW_CODES
          eps 30
          aeps 100

          gap 183413

          begin raw_codes

          name BUTTON1
          4426 4410 569 1627 561 541
          563 1637 562 1637 563 539
          565 537 567 1630 568 537
          568 537 568 1632 571 532
          568 535 569 1626 563 1635
          564 539 565 1637 567 538
          562 1634 565 1632 566 1631
          568 1629 575 528 562 1639
          570 1629 570 1633 565 538
          567 535 589 519 586 512
          593 1604 594 509 595 509
          596 1607 592 1609 590 1602
          567 535 599 505 590 512
          592 511 594 510 594 511
          594 513 591 518 586 1604
          596 1600 568 1632 567 1628
          562 1635 563

          name BUTTON2
          4492 4366
          567 1628 569 532 592 1609
          588 1607 562 541 593 510
          595 1602 597 508 596 509
          595 1606 593 509 596 507
          597 1600 589 1607 592 511
          593 1610 589 516 588 1609
          590 1606 593 1605 564 1632
          567 536 598 1602 597 1602
          597 1606 563 539 595 508
          596 506 589 514 590 1606
          593 509 596 509 600 1601
          594 1603 595 1601 598 504
          590 513 592 510 599 504
          595 509 596 508 596 507
          588 515 589 1611 598 1598
          596 1600 594 1602 597 1601
          567

          end raw_codes

          end remote

          I did that by recognizing two ~4000 length ones as the header of a new button. I deleted the ~5000 length gap between the two buttons. You can continue the process and probably get all the buttons. Let me know how it goes.

          Then when I ran irrecord, I got:

          begin remote

          name MYREMOTE
          bits 48
          flags SPACE_ENC|CONST_LENGTH
          eps 30
          aeps 100

          header 4459 4388
          one 582 1616
          zero 582 519
          ptrail 564
          gap 272054
          toggle_bit_mask 0x0

          begin codes
          BUTTON1 0xB24D7B84E01F
          BUTTON2 0xB24D7B84E01F
          end codes

          end remote

          try it out! Good luck.

          1. I will try this, thanks. I should mention though that that is all output from pressing just one button, the on/off.

          2. Interesting. It’s definitely two distinct packets. Did you press the button twice? There’s probably an On command and an Off command. These A/C units tend to send full packets at each press, so instead of temperature up, temperature down, it’s always “AC to 65 degrees” or something. Anyway let me know how it goes!!

  5. No luck, I am only pressing the button once. The same button is used for both on, and off. If the remote is facing away from the unit and I press the button I have to press it twice to get it back in sync. So, if the unit is on and I press the button facing away from it, then come back and press it facing the unit nothing happens. When I press it a second time it will then turn off.

    Below is me pressing the button for what should be an on signal, wait a seconds, and then pressing it again for what should be an off signal.

    7370948

    4448 4400 568 1628 561 542
    562 1648 551 1637 562 541
    563 539 566 1631 568 537
    574 557 542 1633 565 538
    567 536 568 1629 560 1663
    543 533 565 1638 561 1642
    567 536 569 1632 567 1636
    563 1628 561 1635 564 1634
    565 1633 566 539 565 1632
    567 536 569 534 570 533
    562 541 563 540 565 539
    568 537 565 1632 567 1630
    569 1654 535 541 564 540
    564 540 565 538 566 1637
    562 541 564 539 565 538
    567 1634 565 1631 568 1629
    569 1629 561 5275 4444 4403
    568 1629 570 533 562 1639
    570 1652 537 540 564 540
    565 1631 568 536 568 537
    568 1633 566 536 568 535
    570 1627 562 1634 564 539
    566 1636 563 1640 570 541
    553 1639 570 1628 561 1636
    563 1634 565 1631 568 1631
    568 537 568 1629 570 532
    562 541 564 538 566 537
    568 535 569 536 569 535
    569 1627 562 1635 564 1639
    560 537 568 534 560 543
    562 543 562 1640 569 534
    570 533 561 541 594 1606
    563 1635 564 1632 569 1631
    618

    3423643

    4444 4403 568 1627 562 540
    564 1637 562 1634 565 538
    566 562 543 1654 535 543
    561 570 535 1665 544 532
    562 541 564 1659 540 1629
    569 561 534 1642 567 537
    568 1629 569 1626 564 1633
    565 1631 568 542 562 1631
    569 1629 570 1633 565 537
    568 562 542 566 528 569
    536 1635 564 565 540 538
    566 1663 535 1635 565 1631
    568 535 569 560 535 568
    536 540 565 566 539 539
    565 564 540 536 569 1632
    567 1629 569 1628 562 1635
    563 1635 564 5269 4455 4401
    556 1633 565 539 565 1636
    563 1633 566 537 568 534
    570 1653 536 543 561 543
    562 1639 570 533 562 541
    563 1633 566 1631 568 534
    570 1632 568 537 567 1630
    569 1627 562 1634 565 1631
    567 536 569 1631 568 1630
    569 1641 558 538 566 537
    568 535 569 533 561 1661
    539 538 566 539 573 1629
    563 1633 565 1632 567 535
    570 533 561 541 564 539
    565 540 565 539 565 538
    567 562 542 1631 568 1629
    560 1635 564 1633 566 1633
    616

    1. Here is my “manually-decoded” version of that:

      begin remote

      name MYREMOTE
      flags RAW_CODES
      eps 30
      aeps 100

      gap 183413

      begin raw_codes

      name BUTTON1
      4448 4400 568 1628 561 542
      562 1648 551 1637 562 541
      563 539 566 1631 568 537
      574 557 542 1633 565 538
      567 536 568 1629 560 1663
      543 533 565 1638 561 1642
      567 536 569 1632 567 1636
      563 1628 561 1635 564 1634
      565 1633 566 539 565 1632
      567 536 569 534 570 533
      562 541 563 540 565 539
      568 537 565 1632 567 1630
      569 1654 535 541 564 540
      564 540 565 538 566 1637
      562 541 564 539 565 538
      567 1634 565 1631 568 1629
      569 1629 561

      name BUTTON2
      4444 4403
      568 1629 570 533 562 1639
      570 1652 537 540 564 540
      565 1631 568 536 568 537
      568 1633 566 536 568 535
      570 1627 562 1634 564 539
      566 1636 563 1640 570 541
      553 1639 570 1628 561 1636
      563 1634 565 1631 568 1631
      568 537 568 1629 570 532
      562 541 564 538 566 537
      568 535 569 536 569 535
      569 1627 562 1635 564 1639
      560 537 568 534 560 543
      562 543 562 1640 569 534
      570 533 561 541 594 1606
      563 1635 564 1632 569 1631
      618

      name BUTTON3
      4444 4403 568 1627 562 540
      564 1637 562 1634 565 538
      566 562 543 1654 535 543
      561 570 535 1665 544 532
      562 541 564 1659 540 1629
      569 561 534 1642 567 537
      568 1629 569 1626 564 1633
      565 1631 568 542 562 1631
      569 1629 570 1633 565 537
      568 562 542 566 528 569
      536 1635 564 565 540 538
      566 1663 535 1635 565 1631
      568 535 569 560 535 568
      536 540 565 566 539 539
      565 564 540 536 569 1632
      567 1629 569 1628 562 1635
      563 1635 564

      name BUTTON4
      4455 4401
      556 1633 565 539 565 1636
      563 1633 566 537 568 534
      570 1653 536 543 561 543
      562 1639 570 533 562 541
      563 1633 566 1631 568 534
      570 1632 568 537 567 1630
      569 1627 562 1634 565 1631
      567 536 569 1631 568 1630
      569 1641 558 538 566 537
      568 535 569 533 561 1661
      539 538 566 539 573 1629
      563 1633 565 1632 567 535
      570 533 561 541 564 539
      565 540 565 539 565 538
      567 562 542 1631 568 1629
      560 1635 564 1633 566 1633
      616
      end raw_codes

      end remote

      and here is the result from arecord -i. In this case, it appears that it’s sending double packets. Two “ON” commands the first time, and two “OFF” commands the second time, perhaps?

      begin remote

      name MYREMOTE
      bits 48
      flags SPACE_ENC|CONST_LENGTH
      eps 30
      aeps 100

      header 4447 4401
      one 562 1635
      zero 562 541
      ptrail 589
      gap 272083
      toggle_bit_mask 0x0

      begin codes
      BUTTON1 0xB24DBF40708F
      BUTTON2 0xB24DBF40708F
      BUTTON3 0xB24D7B84E01F
      BUTTON4 0xB24D7B84E01F
      end codes

      end remote

      The EO1F one is the same as I got last time (I didn’t notice BUTTON1 and BUTTON2 were exactly identical). If you load this up in LIRC and have it send two of one or the other of these codes one right after the other, does anything happen?

  6. Good catch, didn’t see those were the same either. Still no luck however, not sure how to send it quick enough. Tried calling it twice in a shell script and watching the LED with a camera and it is noticeably two blink, which isn’t what the remote looks like.

    1. Dang. What a pain. Try:

      irsend SEND_ONCE MYREMOTE BUTTON1 BUTTON1

      or

      irsend SEND_ONCE MYREMOTE BUTTON3 BUTTON3

      I’m not sure how much of a delay that will incur but hopefully not a large one.

        1. Awesome, thanks for the help. I’ll try these when I get home from work tomorrow. I’ll let you know how it goes.

  7. 🙁 still no luck with lirc. However I was able to take the raw code from above, put that into some Arduino code and get the AC to turn off. I am using the same setup as I am on the pi, but can’t get it to work further than about 4 feet. Any idea why?

    I think it is possible the issue I am having with the pi is a range thing. I will try to test this closer and see what happens, but I am not sure I will be able to get the pi/lircs timing quick enough all of the repeat_gaps/gaps I tried I was still able to see two distinct flashes of the LED, not the case on the Arduino.

  8. This is great stuff! Thanks for sharing!
    Your HA interface (especially AC control part) is awesome! Do you mind sharing the configuration?
    Also, I am trying to get the IR transmitter on a ESP8266. Any advice?

    Again, very inspiring post. Thanks!

    1. I just ordered some ESP8266’s to play with, they look awesome. You’d have to code it up to somehow receive over the network the raw timing for the IR code from LIRC and then blink the IR emitter with those precise timings (using one of the GPIOs on the base of a transistor, just like I did with the pi). Let me know if you get that working because it sounds like an excellent idea.

  9. Hi ntouran and thanks for sharing the video, code and everything!

    Don’t you have the problem that the states (of the TV for example) are not recorded such that if you activate the fire_sequence twice, it would actually turn off the tv and stereo?

    1. Hi. Yes that is definitely a problem. You can only do fire_sequence when everything is off in the first place. Fortunately, my stereo always turns on when you press an input selecting button but never turns off so for music I’m lucky and OK. For TV, it’s a challenge. I have a camera that can see the TV so I can check it if I get confused about it being on or off when I’m away.

      Other stereos don’t have the on-only command and they’re a real pain. so you just have to try to keep track of things. Definitely suboptimal.

  10. Hello,

    I’m trying to do the same but I’m facing some problems : how to get the gap parameter ?

    I’m doing a :

    sudo irrecord -a clim.conf > lircd.conf

    to have a more readable file but it returns me :

    irrecord: could not find gap.
    irrecord: decoding of OFF failed

        1. Wow, that’s huge packet! I tried for a while but was not able to process it to codes with irrecord. You might be able to use it as a totally raw conf file though. Give this a whirl as your lircd.conf

          Dunno if it will work or not. Sorry I couldn’t get it.

          1. You too are having the “irrecord: could not find gap” error when trying to process the file (irrecord -a) ?

        2. You don’t have to convert the raw data from mode2 into binaries, just paste the timing figures into lircd.conf as is. I did this for my Toshiba air cond and it works so great!

  11. Hi everyone
    Thanks to Nick’s detailed description i am able to control my air conditioner from the raspberry pi. Now that the that part is done i want to control other air conditioners too. I have 2 Ac’s of the same company(same model) that i want to control independently from the raspberry pi. Is it possible that i can do this

  12. Hi Nick,
    I am trying to set my AC to any temperature using an input slider and IR commands but unable to do it.
    I can turn ON and OFF the AC using scripts but changing the temperature using the input slider is not working for me can you help me in that.

    1. Hey! I have this. Here’s what I did.

      1. Create a shell_command with a template that fills in the number from the slider:

      set_ac_to_slider: ‘irsend SEND_ONCE DELONGHI AC_{{states.input_slider.ac_temperature.state|int}}_AUTO’

      2. Call the command when you want. I made mine so it triggers as a script so I can press a button to have it send the command rather than having it go whenever the slider changes:

      216 ac_set:
      217 alias: Set AC to any value
      218 sequence:
      219 – service: shell_command.set_ac_to_slider

      3. If you really want it to happen whenever you change the slider, make an automation that triggers off the slider state like this:

      624 trigger:
      625 platform: state
      626 entity_id: input_slider.ac_temperature

  13. Could you share some of your Home Assistant configs? I’m really interested in how to get the slider working to control the temp/fan. Please let me know if you still do anything with this project, as I have just built the circuit and I’m trying to get lirc working with home assistant. Any help would be much appreciated.

    1. Sure!
      Here’s the slider:

      input_number:
      ac_temperature:
      name: A/C Setting
      initial: 24
      min: 18
      max: 32
      step: 1

      Then in the shell command section:

      shell_command:
      set_ac_to_slider: 'ssh pi@rpi irsend SEND_ONCE DELONGHI AC_{{states.input_number.ac_temperature.state|int}}_AUTO'

      A script:
      ac_set:
      alias: Set AC to any value
      sequence:
      - service: shell_command.set_ac_to_slider

      Then I just put that script on the UI and press it when I want to apply the slider value.

Leave a Reply

Your email address will not be published. Required fields are marked *