{"id":13801842,"url":"https://github.com/mcauser/micropython-ys-irtm","last_synced_at":"2025-07-28T05:32:53.393Z","repository":{"id":150620718,"uuid":"229187042","full_name":"mcauser/micropython-ys-irtm","owner":"mcauser","description":"MicroPython examples for YS-IRTM 5V NEC Infrared UART transceivers","archived":false,"fork":false,"pushed_at":"2019-12-20T04:08:37.000Z","size":791,"stargazers_count":24,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-04-22T12:33:07.141Z","etag":null,"topics":["esp32","infrared","ir-receiver","ir-transmitter","micropython","nec-protocol","tinypico","uart","ys-irtm"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mcauser.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-12-20T04:01:29.000Z","updated_at":"2024-02-20T07:12:14.000Z","dependencies_parsed_at":"2023-05-06T09:33:09.196Z","dependency_job_id":null,"html_url":"https://github.com/mcauser/micropython-ys-irtm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcauser%2Fmicropython-ys-irtm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcauser%2Fmicropython-ys-irtm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcauser%2Fmicropython-ys-irtm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcauser%2Fmicropython-ys-irtm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mcauser","download_url":"https://codeload.github.com/mcauser/micropython-ys-irtm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227870704,"owners_count":17832435,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esp32","infrared","ir-receiver","ir-transmitter","micropython","nec-protocol","tinypico","uart","ys-irtm"],"created_at":"2024-08-04T00:01:28.517Z","updated_at":"2024-12-03T07:20:42.135Z","avatar_url":"https://github.com/mcauser.png","language":null,"readme":"# MicroPython YS-IRTM\n\nMicroPython examples for YS-IRTM 5V NEC Infrared UART transceivers.\n\n![demo](docs/demo.jpg)\n\nFeatures dual 38KHz 940nm IR TX/RX LEDs and a micro controller which provides a UART interface.\n\nThis 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.\n\n## Examples\n\nTinyPICO ESP32 \u003e Level shifter \u003e YS-IRTM\n\n```python\nimport time\nfrom machine import Pin, UART\nuart = UART(1, tx=14, rx=15, baudrate=9600)\n\n# sniff for a remote\ndef sniff():\n    while True:\n        if uart.any():\n            print(uart.readline())\n\n# eg. received b'\\x00\\xff\\x45'\n\n# replay a remote\ndef replay():\n    uart.write(bytearray(b'\\xa1\\xf1\\x00\\xff\\x45'))\n    uart.read()\n    # read returns b'\\xf1' to say command confirmed\n\n# send a 5 byte packet, return bool if confirmed sent\ndef tx(buf, timeout_ms=1000):\n    uart.write(buf)\n    timeout = time.ticks_ms() + timeout_ms\n    while time.ticks_ms() \u003c timeout:\n        if uart.any():\n            resp = uart.read()\n            if len(resp) \u003e 0:\n                return buf[1] == resp[0]\n        time.sleep_ms(20)\n    print(buf, 'timeout')\n    return False\n\n# send a variable length string by splitting into chunks of 3 data bytes\ndef send_string(value):\n    buf = bytearray(b'\\xa1\\xf1\\x00\\x00\\x00')\n    # pad string to length divisible by 3\n    if len(value) % 3:\n        value += ' ' * (3 - len(value) % 3)\n    for i in range(0,len(value),3):\n        buf[2:] = bytes(value[i:i+3],'utf-8')\n        while not tx(buf):\n            print(buf, 'resend')\n\n# receive a variable length string\n# waits for a gap in received packets before printing\ndef receive_string():\n    while True:\n        last_size = uart.any()\n        if last_size \u003e 0:\n            time.sleep_ms(400) # around 270ms each tx\n            size = uart.any()\n            if last_size == size:\n                print(uart.read())\n                print(time.ticks_diff(time.ticks_ms(), start))\n            else:\n                last_size = size\n        else:\n            time.sleep_ms(20)\n            start = time.ticks_ms()\n\n# on device 1\nreceive_string()\n\n# on device 2\nsend_string('this is not the most efficient way to send lots of text but it works!')\nsend_string('abcdefghijklmnopqrstuvwxyz')\n\n# on device 1\n# b'this is not the most efficient way to send lots of text but it works!'\n# 6402\n# b'abcdefghijklmnopqrstuvwxyz '\n# 2801\n\n# define something to print when a matching code is detected\ncb = {0: {255: {0x45: '1', 0x46: '2', 0x47: '3'}}}\n\n# press a buttons 1, 2 and 3 on a remote\n# button 1 = b'\\x00\\xFF\\x45'\n# button 2 = b'\\x00\\xFF\\x46'\n# button 3 = b'\\x00\\xFF\\x47'\ndef print_button():\n    while True:\n        try:\n            if uart.any():\n                buf = uart.read()\n                if len(buf) == 3:\n                    print(cb[buf[0]][buf[1]][buf[2]])\n                else:\n                    print(buf, 'unexpected length')\n            time.sleep_ms(20)\n        except KeyError:\n            print(buf, 'unexpected key')\n# prints 1, 2, 3\n```\n\nI have a few remotes which work with this IR receiver, see [remotes](remotes.md) for which codes each button sends.\n\n## Pinout\n\nPin | Name | Description\n:--:|:----:|:--------------------------------\n1   | GND  | Ground\n2   | RXD  | UART receive\n3   | TXD  | UART transmit\n4   | VCC  | Supply voltage 5V\n\n## Transmit Protocol\n\nPayload consists of 5 bytes and if accepted, the device will reply with the command byte.\n\nIf the payload is not understood, the device will not respond. Only the command byte is used as confirmation.\n\nPayload = (Address, Command, Data 1, Data 2, Data 3), eg.\n\n```python\n\u003e\u003e\u003e uart.write(bytearray(b'\\xa1\\xf1\\x01\\x02\\x03'))\n\u003e\u003e\u003e print(uart.read())\nb'\\xf1'\n```\n\nThe first two bytes (Address + Command) are for instructing the modules microcontroller. The next 3 data bytes are what's actually transmitted.\n\nWhen you send data `0x00 0xFF 0x45`, what's actually being IR blasted is `0x00 0xFF 0x45 0xBA`. The 4th data byte is automatically appended.\n\n`Leading burst (low), Space (high), Inverse Address (0x00), Address (0xFF), Command (0x45), Inverse Command (0xBA)`\n\nThe 4th byte Inverse Command is calculated automatically from the 3rd data byte Command.\n\nCommand `0x45` = `0b01000101`, each bit inverted is `0b10111010` = `0xBA` Inverse Command.\n\nThere is no validation around the two address bytes (Inverse Address + Address).\nThe 1st data byte does not have to be the inverse of the 2nd data byte.\n\nIf you send `0x11 0x22 0x33`, it's sending `0x11 0x22 0x33 0xCC`. The `0x11` is _supposed to be_ the inverse of `0x22`.\nIt still sends though. I assume this is to make the module more flexible with different IR protocols.\n\n### Device Address\n\nThe 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.\n\nThe default address is `A1` and is changeable with the `F2` command.\nIf you change the device address, eg to `A2`, then try to send to `A1`, the payload will be ignored.\nResend to `A2` and the payload will be accepted and actioned.\n\nIf you change the address, but forget what it is, fear not. There is a failsafe address `FA`.\nIf you have changed your device address and it's not responding, you can use address `FA` to reset it.\nOr just always send to `FA` and ignore the address feature completely.\n\n### Command, Data 1, Data 2 and Data 3\n\n`F1` command to transmit. The 3 data bytes are NEC user code high, user code low, command code.\n\n`F2` command to change address. Data 1 is the new address. Use zeros for Data 2 and 3.\n\n`F3` command to change serial baud rate. Data 1 is the new baud rate (1-4). Use zeros for Data 2 and 3.\n\nBaud rates: `1` = 4800bps, `2` = 9600bps, `3` = 19200bps, `4` = 57600bps.\n\n## Receive Protocol\n\nWhen the recipient device detects a signal, it will send the 3 data bytes over UART.\n\nTwo address bytes and a command byte. The inverse command byte is not sent over UART.\n\nYou can receive from a remote that uses the NEC protocol, or from a second YS-IRTM module.\n\nNEC repeat codes are not supported. Holding down a button on a remote does nothing and you only get a single capture.\n\n**Sender YS-IRTM:**\n\n```python\n\u003e\u003e\u003e uart.write(bytearray(b'\\xa1\\xf1\\x01\\x02\\x03'))\n\u003e\u003e\u003e print(uart.read())\nb'\\xf1'\n```\n\n**Receiver YS-IRTM:**\n\n```python\n\u003e\u003e\u003e print(uart.read())\nb'\\x01\\x02\\x03'\n```\n\n## Examples\n\nAddress | Command | Data 1 | Data 2 | Data 3 | Description                              | Response\n------- | ------- | ------ | ------ | ------ | ---------------------------------------- | --------\nA1      | F1      | 01     | 02     | 03     | transmit 01 02 03                        | F1\nA1      | F1      | AA     | BB     | CC     | transmit AA BB CC                        | F1\nFA      | F1      | BB     | CC     | DD     | transmit BB CC DD using failsafe addr    | F1\nAB      | F1      | 01     | 02     | 03     | unknown addr AB, packet ignored          | -\nA1      | F2      | A2     | 00     | 00     | change addr from A1 to A2                | F2\nA1      | F2      | A3     | 00     | 00     | unknown addr A1, packet ignored          | -\nFA      | F2      | A1     | 00     | 00     | change addr from A2 to A1 using failsafe | -\nA1      | F3      | 01     | 00     | 00     | set baud rate 4800bps                    | F3\nA1      | F3      | 02     | 00     | 00     | set baud rate 9600bps                    | F3\nA1      | F3      | 03     | 00     | 00     | set baud rate 19200bps                   | F3\nA1      | F3      | 04     | 00     | 00     | set baud rate 57600bps                   | F3\n\n## Saleae Logic Analyser Capture\n\nConnected a [TL1838 IR receiver module](https://www.aliexpress.com/item/32967589687.html) to a [Saleae logic analyser](https://www.saleae.com/), powered by 5V and captured the signal pin.\n\n### Capture 1\n\nBlack remote with blue d-pad at bottom - button 1.\n\nReceived `0x00 0xFF 0x45` over UART.\n\nReceived `0x00 0xFF 0x45 0xBA` over IR.\n\n[capture 1](docs/saleae/remote_8_MHz_24_M_Samples.logicdata)\n\n![capture 1](docs/saleae/saleae-remote.jpg)\n\n### Capture 2\n\nReplay remote button 1 with YS-IRTM.\n\nSent `0x00 0xFF 0x45` over UART.\n\nSent `0x00 0xFF 0x45 0xBA` over IR.\n\n[capture 2](docs/saleae/transmit_8_MHz_24_M_Samples.logicdata)\n\n![capture 2](docs/saleae/saleae-transmit.jpg)\n\n### Capture 3\n\nSent `0x11 0x22 0x33` over UART.\n\nSent `0x11 0x22 0x33 0xCC` over IR.\n\n[capture 3](docs/saleae/11-22-33_8_MHz_24_M_Samples.logicdata)\n\n![capture 3](docs/saleae/saleae-11-22-33.jpg)\n\n### Capture 4\n\nSent `0x12 0x34 0x56` over UART.\n\nSent `0x12 0x34 0x56 0xA9` over IR.\n\n[capture 4](docs/saleae/12-34-56_8_MHz_24_M_Samples.logicdata)\n\n![capture 4](docs/saleae/saleae-12-34-56.jpg)\n\n## Parts\n\n* [YS-IRTM](https://www.aliexpress.com/item/32647529087.html) $2.09 AUD\n* [TinyPICO](https://www.tinypico.com/) $20.00 USD\n* [Logic level converter](https://www.aliexpress.com/item/32589088559.html) $0.45 AUD\n* [TL1838 IR receiver module](https://www.aliexpress.com/item/32967589687.html) $0.27 AUD\n* [Saleae Logic 8](https://www.saleae.com) $639 AUD\n\n## Links\n\n* [micropython.org](http://micropython.org)\n* [Schematics](docs/schematics.pdf)\n* [TinyPICO Getting Started](https://www.tinypico.com/gettingstarted)\n\n## License\n\nLicensed under the [MIT License](http://opensource.org/licenses/MIT).\n\nCopyright (c) 2019 Mike Causer\n","funding_links":[],"categories":["Libraries"],"sub_categories":["Communications"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcauser%2Fmicropython-ys-irtm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmcauser%2Fmicropython-ys-irtm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcauser%2Fmicropython-ys-irtm/lists"}