dotnet / iot

This repo includes .NET Core implementations for various IoT boards, chips, displays and PCBs.
MIT License
2.16k stars 582 forks source link

Is there an example of infrared transmitter and receiver remote control? #1231

Open bbhxwl opened 3 years ago

bbhxwl commented 3 years ago

Is there an example of infrared transmitter and receiver remote control?

pgrawehr commented 3 years ago

No, these are not supported yet.

I've got LIRC working on my Pi already, but writing a binding that connects to it is on my to-do list still.

Here's some prelimary help on getting the first part set up (unfortunatelly, it's quite a lot of steps, and most information on the internet fails to tell you that the sender and receiver are completelly distinct and need to be considered as two separate devices).

How to set up LIRC on the Raspberry Pi (Prelimary)

To get LIRC running on the Raspberry Pi with the latest Raspbian release (Buster), a bit of tweaking is necessary, due to recent incompatible changes in the kernel. It's best to follow these https://www.raspberrypi.org/forums/viewtopic.php?t=235256 step-by-step instructions. After following those instructions, you will get two device nodes: /dev/lirc0 is the sender, /dev/lirc1 the receiver. Depending on which is active, you'll be able to either test the receiver using irw or the sender using irsend. If you need both services, test them separtelly now by changing the line device= in /etc/lirc/lirc_options.conffrom/dev/lirc0to /dev/lirc1 or vice-versa and restart the service (using sudo systemctl restart lircd). Note: To see that the sender is working, it may be helpful to temporarily replace the IR-LED with an ordinary LED.

After all this trouble, I've got this lirc_options.conf file:

# These are the default options to lircd, if installed as
# /etc/lirc/lirc_options.conf. See the lircd(8) and lircmd(8)
# manpages for info on the different options.
#
# Some tools including mode2 and irw uses values such as
# driver, device, plugindir and loglevel as fallback values
# in not defined elsewhere.

[lircd]
nodaemon        = False
driver          = default
device          = /dev/lirc0
output          = /var/run/lirc/lircd0
pidfile         = /var/run/lirc/lircd0.pid
plugindir       = /usr/lib/arm-linux-gnueabihf/lirc/plugins
permission      = 666
allow-simulate  = No
repeat-max      = 600
#effective-user =
listen         = 2221 # Important: We will need this later
#connect        = host[:port]
#loglevel       = 6
#release        = true
#release_suffix = _EVUP
#logfile        = ...
#driver-options = ...

[lircmd]
uinput          = False
nodaemon        = False

# [modinit]
# code = /usr/sbin/modprobe lirc_serial
# code1 = /usr/bin/setfacl -m g:lirc:rw /dev/uinput
# code2 = ...

# [lircd-uinput]
# add-release-events = False
# release-timeout    = 200
# release-suffix     = _EVUP

I've also got an /etc/lirc/lirc.conf file for my remote, which I created using irrecord, but you might be more fortunate and find one that matches your particular remote.

Now I copied the above file to /etc/lirc/lirc_options1.conf and replace these lines:


device          = /dev/lirc1
#Note that we leave this on default, will simplify usage of irw.
output          = /var/run/lirc/lircd
pidfile         = /var/run/lirc/lircd1.pid
listen         = 2222 # Important: We will need this later

Now, once the service (for /dev/lirc0) runs, we can test it again: irsend -a localhost:2221 SEND_ONCE <Remote> KEY_GREEN should blink the LED (gives a bunch of errors, but works). Then we now start the receiver as well: sudo lircd --nodaemon -O /etc/lirc/lirc_options1.conf. This should start the service in foreground mode and show any problems (i.e. if you get an error saying there is already another lirc process running, check that the two have different pidfile entries). Now start irw, and check that pressing keys on the remote gives the expected results.

After that, both input and output work at the same time. The only thing that we now still want to do is set up the second service to start automatically at bootup as well. Let's do a copy of the service description: `sudo cp /lib/systemd/system/lircd.service /lib/systemd/system/lircd1.service' and change it to:

[Unit]
Documentation=man:lircd(8)
Documentation=http://lirc.org/html/configure.html
Description=Flexible IR remote input application support on /dev/lirc1
Wants=lircd-setup.service
After=network.target lircd-setup.service

[Service]
Type=notify
ExecStart=/usr/sbin/lircd --nodaemon -O /etc/lirc/lirc_options1.conf
; User=lirc
; Group=lirc

; Hardening opts, see systemd.exec(5). Doesn't add much unless
; not running as root.
;
; # Required for dropping privileges in --effective-user.
; MemoryDenyWriteExecute=true
; NoNewPrivileges=true
; PrivateTmp=true
; ProtectHome=true
; ProtectSystem=full

[Install]
WantedBy=multi-user.target

Finally prepare it for autostart and start it with sudo systemctl enable lirc1 sudo systemctl start lirc1

sudo lircmd -s /var/run/lirc/lircd --options-file=/etc/lirc/lirc_options1.conf --uinput --nodaemon --loglevel=10

bbhxwl commented 3 years ago

Hope that net 5 can fully support, in order to make C# better and better.

Ellerbach commented 3 years ago

For emission, you can use SPI. You just build in the memory the full array with the shape of the signal and you adjust the SPI clock to be close to what you need. I've done that to reimplement the infrared Lego protocol to control my train bu anything else that Lego supports as well. You have a full example here for the code side: https://github.com/Ellerbach/LegoTrain/blob/master/LegoTrain/LegoTrain/Infrared.cs The basic electronic part: https://github.com/Ellerbach/LegoTrain#infrared Note: this code originally worked perfectly on a Netduino then a Raspi running Windows 10 IoT. I haven't ported it (yet) to .NET IoT but it will work the exact same way. Using SPI with an array in memory for anything you want to output with a very precise frequency is really working well. Even better for infrared as you usually have 20 to 30% tolerance for the frequency. Some SPI may not be able (like RPI) to be setup to a very precise frequency.

bbhxwl commented 3 years ago

Are there any more convenient examples now? I want to dock the remote control.

pgrawehr commented 3 years ago

@bbhxwl Unfortunately no. I did not have time for this.

krwq commented 3 years ago

@bbhxwl infrared usually requires precise reading to be reliable (unless you don't care about sometimes having to press the button twice) - since Raspberry Pi is running on linux and the process can get interrupted at any moment we can't guarantee reliable reading. The way I've done that in the past was to have Arduino reading IR and then sending the messages over serial port to other device (I had connected arduino with USB to my PC) - serial port can be done relatively reliably and that has worked fine for me.

I bet it's possible to do it still with SPI but it will require a bit of playing to do (and you may still get ocassional hickups).

krwq commented 1 year ago

[Triage] we need to make sure documentation mentions that there might be issues due to non real-time. Sending can probably done relatively reliably with SPI