Skip to content

Instantly share code, notes, and snippets.

@andrewcchen
Last active November 1, 2025 16:08
Show Gist options
  • Select an option

  • Save andrewcchen/f16eb20d19ea64d9f997c470e2addeaa to your computer and use it in GitHub Desktop.

Select an option

Save andrewcchen/f16eb20d19ea64d9f997c470e2addeaa to your computer and use it in GitHub Desktop.
Encode an NEC IR command into code for Tuya ZS06/ZS08/TS1201
/*
Encode an NEC IR command into code for Tuya ZS06/ZS08/TS1201
Usage: encode_nec("<four bytes in hex, two bytes of address followed by two bytes of command>")
If your address and/or command is just one byte (8 bits), append the complement of the byte after it to make it two bytes.
Example:
encode_nec("04fb08f7") // encodes nec address 0x04 and command 0x08
See:
https://www.sbprojects.net/knowledge/ir/nec.php
https://www.zigbee2mqtt.io/devices/ZS06.html
https://github.com/Koenkk/zigbee2mqtt/issues/11633
mildsunrise describes how the encoding works in:
https://gist.github.com/mildsunrise/1d576669b63a260d2cff35fda63ec0b5
In short, the signal is described in terms of alternating on/off (first on) times in microseconds encoded in little-endian 16-bit integers, which is then compressed with FastLZ.
This encoded only generates literal blocks, which are up to 32 bytes of data long each, prefixed by a 1 byte length field.
*/
function encode_nec(hex) {
function le(x) {
x = x & 0xffff;
return [ x & 0xff, x >> 8 ];
}
// for NECx2 devices (e.g. samsung tv) replace 9000 with 4500
let output = [ 4-1, ...le(9000), ...le(4500) ];
for (const x of Buffer.from(hex, 'hex')) {
output.push(32-1);
for (let i = 0; i < 8; i++) {
output.push(...le(560));
if (x & (1 << i)) {
output.push(...le(2250-560));
} else {
output.push(...le(1125-560));
}
}
}
output.push(2-1, ...le(560));
return Buffer.from(new Uint8Array(output)).toString('base64');
}
@mildsunrise
Copy link

mildsunrise commented Feb 6, 2024

for anyone landing here: I've managed to understand the weird compression scheme used by this thing!
I've documented everything here:

https://gist.github.com/mildsunrise/1d576669b63a260d2cff35fda63ec0b5

and also provided a function to decompress the signal in case someone wants to investigate what's in their learnt codes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment