Skip to content

Instantly share code, notes, and snippets.

@K4zoku
Created September 15, 2026 18:30
Show Gist options
  • Select an option

  • Save K4zoku/b10bb399d58d5d58b7d494da7853b3ca to your computer and use it in GitHub Desktop.

Select an option

Save K4zoku/b10bb399d58d5d58b7d494da7853b3ca to your computer and use it in GitHub Desktop.
HyperWork Luna (HPWDL01) 433 MHz desk lamp remote protocol
/*
* HPWDL01.h - HyperWork Luna (HPWDL01) 433 MHz desk lamp remote protocol.
*
* SPDX-License-Identifier: CC0-1.0
*
* Wire protocol reverse-engineered from stock remote captures.
* Dedicated to the public domain under CC0 1.0: free to copy, modify,
* reuse and redistribute for any purpose, no attribution required.
* https://creativecommons.org/publicdomain/zero/1.0/
*
* Pure ISO C: no platform or hardware dependencies. Radio setup VALUES
* live here; applying them to a transceiver and driving the data line
* stay in the application.
*
* Transport: 433.92 MHz OOK carrier at 2.4 kbaud, asynchronous serial
* data on one GPIO. HIGH = carrier on, LOW = carrier off.
*
* Payload: 24-bit code, sent MSB first, OOK pulse-length coded:
* code = HPWDL01_PREFIX << 8 | command
*
* One frame:
* 1. HIGH HPWDL01_LEADER_US (preamble)
* 2. LOW HPWDL01_START_GAP_US (sync gap)
* 3. 24 bits, MSB first; each bit = time HIGH, then time LOW:
* bit 1 -> HIGH HPWDL01_LONG_US, LOW HPWDL01_SHORT_US
* bit 0 -> HIGH HPWDL01_SHORT_US, LOW HPWDL01_LONG_US
* 4. the last bit ends HIGH; HPWDL01_GAP_US runs with the line
* still HIGH (carrier on), then the next repeated frame starts
*
* All timings are microseconds.
*/
#ifndef HPWDL01_H
#define HPWDL01_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Radio transport parameters:
* 433.92 MHz OOK carrier, 2.4 kbaud asynchronous serial data line. */
#define HPWDL01_RF_FREQ_MHZ 433.92f
#define HPWDL01_TX_DATA_RATE_KBAUD 2.4f
#define HPWDL01_MODULATION 2 /* ASK/OOK */
#define HPWDL01_CC_MODE 0 /* infinite packet mode */
#define HPWDL01_PKT_FORMAT 3 /* asynchronous serial mode */
#define HPWDL01_IOCFG0_GDO0_TX 0x0D /* data pin = async serial TX stream */
/* Bit / frame timing (us) */
#define HPWDL01_SHORT_US 430
#define HPWDL01_LONG_US 1280
#define HPWDL01_LEADER_US 1100
#define HPWDL01_START_GAP_US 12000
#define HPWDL01_GAP_US 12080
/* 24-bit payload: HPWDL01_PREFIX << 8 | command */
#define HPWDL01_PREFIX 0x1397UL
/* Command table (X-macro): HPWDL01_X(name, commandByte).
* The stock remote also knows COLOR_ALT (0x55), same effect as COLOR. */
#define HPWDL01_COMMAND_TABLE(X) \
X(COLOR, 0xAA) \
X(COLOR_ALT, 0x55) \
X(BRIGHTNESS_UP, 0xAD) \
X(BRIGHTNESS_DOWN, 0x05) \
X(OFF, 0xFF)
/* 8-bit command bytes. */
enum {
#define HPWDL01_X(name, byte) HPWDL01_CMD_##name = (byte),
HPWDL01_COMMAND_TABLE(HPWDL01_X)
#undef HPWDL01_X
};
/* Actual 24-bit wire codes: HPWDL01_PREFIX << 8 | command byte. */
enum {
#define HPWDL01_X(name, byte) \
HPWDL01_CODE_##name = ((uint32_t)HPWDL01_PREFIX << 8) | (uint32_t)(byte),
HPWDL01_COMMAND_TABLE(HPWDL01_X)
#undef HPWDL01_X
};
/* Frames per burst for each action */
#define HPWDL01_COLOR_REPEATS 2
#define HPWDL01_BRIGHTNESS_BASE_REPEATS 1
#define HPWDL01_OFF_REPEATS 22
#define HPWDL01_BRIGHTNESS_MAX_LEVEL 10
/* One payload bit on the wire: time HIGH, then time LOW. */
typedef struct {
uint16_t highUs;
uint16_t lowUs;
} HPWDL01_BitPulse;
static inline HPWDL01_BitPulse HPWDL01_bitPulse(uint8_t bit)
{
/* Row 0 = bit 0, row 1 = bit 1. */
static const HPWDL01_BitPulse PULSES[2] = {
{HPWDL01_SHORT_US, HPWDL01_LONG_US},
{HPWDL01_LONG_US, HPWDL01_SHORT_US}
};
return PULSES[bit != 0];
}
#ifdef __cplusplus
}
#endif
#endif /* HPWDL01_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment