Home

Awesome

MicroPython YS-IRTM

MicroPython examples for YS-IRTM 5V NEC Infrared UART transceivers.

demo

Features dual 38KHz 940nm IR TX/RX LEDs and a micro controller which provides a UART interface.

This is a 5V logic device, so if you wish to use with a 3V3 MCU such as the ESP32, you'll need a level shifter or voltage divider.

Examples

TinyPICO ESP32 > Level shifter > YS-IRTM

import time
from machine import Pin, UART
uart = UART(1, tx=14, rx=15, baudrate=9600)

# sniff for a remote
def sniff():
    while True:
        if uart.any():
            print(uart.readline())

# eg. received b'\x00\xff\x45'

# replay a remote
def replay():
    uart.write(bytearray(b'\xa1\xf1\x00\xff\x45'))
    uart.read()
    # read returns b'\xf1' to say command confirmed

# send a 5 byte packet, return bool if confirmed sent
def tx(buf, timeout_ms=1000):
    uart.write(buf)
    timeout = time.ticks_ms() + timeout_ms
    while time.ticks_ms() < timeout:
        if uart.any():
            resp = uart.read()
            if len(resp) > 0:
                return buf[1] == resp[0]
        time.sleep_ms(20)
    print(buf, 'timeout')
    return False

# send a variable length string by splitting into chunks of 3 data bytes
def send_string(value):
    buf = bytearray(b'\xa1\xf1\x00\x00\x00')
    # pad string to length divisible by 3
    if len(value) % 3:
        value += ' ' * (3 - len(value) % 3)
    for i in range(0,len(value),3):
        buf[2:] = bytes(value[i:i+3],'utf-8')
        while not tx(buf):
            print(buf, 'resend')

# receive a variable length string
# waits for a gap in received packets before printing
def receive_string():
    while True:
        last_size = uart.any()
        if last_size > 0:
            time.sleep_ms(400) # around 270ms each tx
            size = uart.any()
            if last_size == size:
                print(uart.read())
                print(time.ticks_diff(time.ticks_ms(), start))
            else:
                last_size = size
        else:
            time.sleep_ms(20)
            start = time.ticks_ms()

# on device 1
receive_string()

# on device 2
send_string('this is not the most efficient way to send lots of text but it works!')
send_string('abcdefghijklmnopqrstuvwxyz')

# on device 1
# b'this is not the most efficient way to send lots of text but it works!'
# 6402
# b'abcdefghijklmnopqrstuvwxyz '
# 2801

# define something to print when a matching code is detected
cb = {0: {255: {0x45: '1', 0x46: '2', 0x47: '3'}}}

# press a buttons 1, 2 and 3 on a remote
# button 1 = b'\x00\xFF\x45'
# button 2 = b'\x00\xFF\x46'
# button 3 = b'\x00\xFF\x47'
def print_button():
    while True:
        try:
            if uart.any():
                buf = uart.read()
                if len(buf) == 3:
                    print(cb[buf[0]][buf[1]][buf[2]])
                else:
                    print(buf, 'unexpected length')
            time.sleep_ms(20)
        except KeyError:
            print(buf, 'unexpected key')
# prints 1, 2, 3

I have a few remotes which work with this IR receiver, see remotes for which codes each button sends.

Pinout

PinNameDescription
1GNDGround
2RXDUART receive
3TXDUART transmit
4VCCSupply voltage 5V

Transmit Protocol

Payload consists of 5 bytes and if accepted, the device will reply with the command byte.

If the payload is not understood, the device will not respond. Only the command byte is used as confirmation.

Payload = (Address, Command, Data 1, Data 2, Data 3), eg.

>>> uart.write(bytearray(b'\xa1\xf1\x01\x02\x03'))
>>> print(uart.read())
b'\xf1'

The first two bytes (Address + Command) are for instructing the modules microcontroller. The next 3 data bytes are what's actually transmitted.

When you send data 0x00 0xFF 0x45, what's actually being IR blasted is 0x00 0xFF 0x45 0xBA. The 4th data byte is automatically appended.

Leading burst (low), Space (high), Inverse Address (0x00), Address (0xFF), Command (0x45), Inverse Command (0xBA)

The 4th byte Inverse Command is calculated automatically from the 3rd data byte Command.

Command 0x45 = 0b01000101, each bit inverted is 0b10111010 = 0xBA Inverse Command.

There is no validation around the two address bytes (Inverse Address + Address). The 1st data byte does not have to be the inverse of the 2nd data byte.

If you send 0x11 0x22 0x33, it's sending 0x11 0x22 0x33 0xCC. The 0x11 is supposed to be the inverse of 0x22. It still sends though. I assume this is to make the module more flexible with different IR protocols.

Device Address

The device has a feature where you can give the module an address (0-255) and it will ignore UART lines that do not begin with the address.

The default address is A1 and is changeable with the F2 command. If you change the device address, eg to A2, then try to send to A1, the payload will be ignored. Resend to A2 and the payload will be accepted and actioned.

If you change the address, but forget what it is, fear not. There is a failsafe address FA. If you have changed your device address and it's not responding, you can use address FA to reset it. Or just always send to FA and ignore the address feature completely.

Command, Data 1, Data 2 and Data 3

F1 command to transmit. The 3 data bytes are NEC user code high, user code low, command code.

F2 command to change address. Data 1 is the new address. Use zeros for Data 2 and 3.

F3 command to change serial baud rate. Data 1 is the new baud rate (1-4). Use zeros for Data 2 and 3.

Baud rates: 1 = 4800bps, 2 = 9600bps, 3 = 19200bps, 4 = 57600bps.

Receive Protocol

When the recipient device detects a signal, it will send the 3 data bytes over UART.

Two address bytes and a command byte. The inverse command byte is not sent over UART.

You can receive from a remote that uses the NEC protocol, or from a second YS-IRTM module.

NEC repeat codes are not supported. Holding down a button on a remote does nothing and you only get a single capture.

Sender YS-IRTM:

>>> uart.write(bytearray(b'\xa1\xf1\x01\x02\x03'))
>>> print(uart.read())
b'\xf1'

Receiver YS-IRTM:

>>> print(uart.read())
b'\x01\x02\x03'

Examples

AddressCommandData 1Data 2Data 3DescriptionResponse
A1F1010203transmit 01 02 03F1
A1F1AABBCCtransmit AA BB CCF1
FAF1BBCCDDtransmit BB CC DD using failsafe addrF1
ABF1010203unknown addr AB, packet ignored-
A1F2A20000change addr from A1 to A2F2
A1F2A30000unknown addr A1, packet ignored-
FAF2A10000change addr from A2 to A1 using failsafe-
A1F3010000set baud rate 4800bpsF3
A1F3020000set baud rate 9600bpsF3
A1F3030000set baud rate 19200bpsF3
A1F3040000set baud rate 57600bpsF3

Saleae Logic Analyser Capture

Connected a TL1838 IR receiver module to a Saleae logic analyser, powered by 5V and captured the signal pin.

Capture 1

Black remote with blue d-pad at bottom - button 1.

Received 0x00 0xFF 0x45 over UART.

Received 0x00 0xFF 0x45 0xBA over IR.

capture 1

capture 1

Capture 2

Replay remote button 1 with YS-IRTM.

Sent 0x00 0xFF 0x45 over UART.

Sent 0x00 0xFF 0x45 0xBA over IR.

capture 2

capture 2

Capture 3

Sent 0x11 0x22 0x33 over UART.

Sent 0x11 0x22 0x33 0xCC over IR.

capture 3

capture 3

Capture 4

Sent 0x12 0x34 0x56 over UART.

Sent 0x12 0x34 0x56 0xA9 over IR.

capture 4

capture 4

Parts

Links

License

Licensed under the MIT License.

Copyright (c) 2019 Mike Causer