s0_Blog

Mercator ceiling fan remote 433MHz protocol

RC switch type with timing:

Time per pulse: 320µs
Sync: [36, 1]
Zero: [1, 2]
One:  [3, 1] # but when transmitting, [2, 1] works also.
Inverted: true # i.e. it goes low-high not high-low

TL;DR: How to send the codes using ESPHome remote_transmitter

...
# Example of using a physical button press to trigger sending the code -- you could use any other component that supports `on_xxx` events.
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO9
      mode:
        input: true
        pullup: true
      inverted: true
    name: rfclick
    internal: true
    on_click: 
      then:
       # Light toggle
        - remote_transmitter.transmit_rc_switch_raw: 
            code: '010001111110'
            protocol:
              pulse_length: 320
              sync: [36, 1]
              zero: [1, 2]
              one: [3, 1]
              inverted: true
            repeat:
              times: 5
              wait_time: 0ms
...

Packet Structure

Sync 1b Preamble 1b Address 4b (Little Endian inverted) Fan control 6b (inverted) Light control 1b (inverted)
(00...) 1 0 xxxx xxxxxx x

Commands

Command Fan Control Light Control
Toggle Light 111111 0
Fan Off 111110 1
Fan High 101111 1
Fan Medium 110111 1
Fan Low 111011 1

Reverse engineering

The structure as described above uses a variable-length off-on pulse for zero and one. Because these are always divisible by the pulse length, they can be decoded 'raw' in URH by setting the samples per bit to align with the pulse length. This is the longer bitstring in the reverse engineering values below, of equal length pulses. I was sampling at 1.8 Msps, and meant that 516 samples (corresponding to one pulse) equals approximately 290 µs per pulse. There's some flexibility in the clocking; 320µs seems to be a fairly common number and works fine.

Looking at the sequence, it's clear that it always begins with a single 1 preceded by some number of 0s (trimmed), as a sync. This produces the semi-arbitrary [36, 1] sync type. Then it's always a pattern of 011 and 0001. Clearly these are two symbols for encoding a real message 0 or 1. These each start with a low pulse, not a high pulse, so are inverted compared to the 'standard' RC behaviour. This corresponds to the the above RC type definition of { zero: [1,2], one: [3,1], inverted: true }.

Looking at the commands breakdown, it's could be phrased to say that 0 in a bit position means 'trigger', and 1 means 'ignore', basically. So 0 in the light control bit always toggles the light value (after a short gap of no transmissions -- it doesn't toggle it for every single packet), or if it's 1, doesn't change the light. There's no obvious way to set the light to a specific value.

Addressing with DIP switch

all 0s/unset

10110001000100010001000100010001000100010001011
s011111111110

bit 1 set

1011011000100010001000100010001000100010001011
s001111111110

bit 2 set

1011000101100010001000100010001000100010001011
s010111111110

bit 3 set

1011000100010110001000100010001000100010001011
s011011111110

bit 4 set

1011000100010001011000100010001000100010001011
s011101111110

all bits set

1011011011011011000100010001000100010001011
s000001111110

Commands

Light toggle

10110001011011011000100010001000100010001011
s010001111110

Fan off

10110001011011011000100010001000100010110001
s010001111101

Fan High

10110001011011011000101100010001000100010001
s010001011111

Fan Medium

10110001011011011000100010110001000100010001
s010001101111

Fan Low

10110001011011011000100010001011000100010001
s010001110111

Tools

Used GQRX to capture Raw IQ data from RTL-SDR And then URH (Universal Radio Hacker) to analyse the data.

URH%20mercator%20signal%20decoding

Pls do not come to my house and turn my fan on randomly xoxo