Skip to content

Instantly share code, notes, and snippets.

@stecman stecman/ir_remote.py
Last active Jul 6, 2016

Embed
What would you like to do?
Raspberry PI hardwired IR remote
#!/usr/bin/env python3
# Experiment: Replacing the LED in an infrared remote with a wired connection
#
# Details of the hardware/software implementation:
#
# I've hard-wired the crappy IR remote that came with a DVB-T RTL-SDR
# dongle into a GPIO pin on the Raspberry Pi. The infrared LED in the
# remote has been removed and replaced with a wire going to GPIO 3.
#
# Since the signal to infrared LED contains a carrier wave, I used a
# 10uf capacitor (the only capacitor I had on hand) in the circuit to
# change the carrier wave into constant LOW when broadcasting, and
# constant HIGH when not broadcasting. There's also a 10k resistor for
# a ground reference.
#
# Even though this code uses timing based on guesses, it reliably reads
# signals from the remote. I'm not sure what the actual encoding used by
# the remote is, but it appears to be timing based, with the pin brought
# low for either ~60 or ~160 microseconds at a time. This interpretation
# creates pairs of either "11" or "01", which I'm using as 1 and 0
# respectively.
#
# With this interpretation, the data goes high for one byte, then low for
# one byte, followed by a byte of data, and a byte that is the complement
# of the data byte. Transmissions start with an additional four bits "1001",
# though this isn't as reliably read, so I discard it. "1001" is also broadcast
# when any button is held down, so it's possible this is the actual preamble,
# and thev alue I'm using as a preamble is something else.
#
# This implemenation was a quick experiment, so I've hacked binary data collection
# in using strings. If I decide to use this for something, I'll update this Gist
# to pack incoming data properly as binary for better performance.
import RPi.GPIO as gpio
import time
import sys
INFRARED_PIN = 3
PREAMBLE = 0xff00 # Signal this remote sends before commands
BUTTON_POWER = 0x4d
BUTTON_SOURCE = 0xd5
BUTTON_MUTE = 0x97
BUTTON_RECORD = 0xcd
BUTTON_TIMESHIFT = 0xcf
BUTTON_FULLSCREEN = 0xfd
BUTTON_VOL_MINUS = 0xaf
BUTTON_VOL_PLUS = 0x87
BUTTON_CH_PLUS = 0x5f
BUTTON_CH_MINUS = 0xbf
BUTTON_RECALL = 0xc7
BUTTON_NUM_0 = 0xb7
BUTTON_NUM_1 = 0x6f
BUTTON_NUM_2 = 0x47
BUTTON_NUM_3 = 0x7
BUTTON_NUM_4 = 0x4f
BUTTON_NUM_5 = 0x67
BUTTON_NUM_6 = 0x27
BUTTON_NUM_7 = 0x77
BUTTON_NUM_8 = 0x57
BUTTON_NUM_9 = 0x17
gpio.setmode(gpio.BOARD) # Using pin numbers on the board
gpio.setup(INFRARED_PIN, gpio.IN) # Set IR pin to input
while True:
buf = ""
highCount = 0
while gpio.input(INFRARED_PIN) == gpio.HIGH:
time.sleep(0.01)
lastValue = 1 # The last read was high before it changed just now
lastChange = time.perf_counter()
while highCount < 10000:
value = gpio.input(INFRARED_PIN)
if value != lastValue:
now = time.perf_counter()
duration = round((now - lastChange) * 10000)
# This is terrible and fragile
#
# Need to replace time based check with something that automatically
# determines long and short pulse length (in case the CPU is busy while
# running this program, which messes up the timing)
if duration < 12:
buf += "1"
else:
buf += "0"
lastValue = value
lastChange = now
if len(buf) >= 68:
break
if value == gpio.HIGH:
highCount += 1
else:
highCount = 0
if len(buf) < 68:
# Ignore repeats and too small signals
# There are 64 bits of data, but all signals start with 1001
#
# A one preceeding a zero only happens at the start of a transmission
# so I'm guessing this is part of the preamble, but I'm ignoring it
continue
# Remove preamble and convert carier to bits
# This gives us four bytes in binary if the signal was ok
# Need to rewrite this to do this without strings as part of reading the pin
buf = buf[4:].replace("01", "0").replace("11", "1")
message = int(buf, 2)
if not (message >> 16) & PREAMBLE:
print("Stream doesn't match expected preamble: %s" % buf)
continue
# We only care about the last two bytes
data = 0xFFFF & message
# Code is most significant two bytes
code = data >> 8
# Binary inverse of code is least significant two bytes
parity = 0xFF & data
if code & parity != 0x0:
print("Parity and code did not match: %s" % buf)
# Demo to confirm it's all working
print("Incoming binary: %s" % buf)
if code == BUTTON_POWER:
print("Pressed POWER")
elif code == BUTTON_SOURCE:
print("Pressed SOURCE")
elif code == BUTTON_MUTE:
print("Pressed MUTE")
elif code == BUTTON_RECORD:
print("Pressed RECORD")
elif code == BUTTON_TIMESHIFT:
print("Pressed TIMESHIFT")
elif code == BUTTON_FULLSCREEN:
print("Pressed FULLSCREEN")
elif code == BUTTON_VOL_MINUS:
print("Pressed VOL_MINUS")
elif code == BUTTON_VOL_PLUS:
print("Pressed VOL_PLUS")
elif code == BUTTON_CH_PLUS:
print("Pressed CH_PLUS")
elif code == BUTTON_CH_MINUS:
print("Pressed CH_MINUS")
elif code == BUTTON_RECALL:
print("Pressed RECALL")
elif code == BUTTON_NUM_0:
print("Pressed NUM_0")
elif code == BUTTON_NUM_1:
print("Pressed NUM_1")
elif code == BUTTON_NUM_2:
print("Pressed NUM_2")
elif code == BUTTON_NUM_3:
print("Pressed NUM_3")
elif code == BUTTON_NUM_4:
print("Pressed NUM_4")
elif code == BUTTON_NUM_5:
print("Pressed NUM_5")
elif code == BUTTON_NUM_6:
print("Pressed NUM_6")
elif code == BUTTON_NUM_7:
print("Pressed NUM_7")
elif code == BUTTON_NUM_8:
print("Pressed NUM_8")
elif code == BUTTON_NUM_9:
print("Pressed NUM_9")
else:
print("Got code %s and not sure what to do" % hex(code))
print("")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.