jesserockz / wizmote-esphome

65 stars 30 forks source link

Button number changes on each key press #5

Open drbiosignals opened 2 years ago

drbiosignals commented 2 years ago

Hallo and congratulations for the great work.

I flashed an esp32 with wizmote-esphome and I tested two remotes. I have the great problem with both remotes. MAC address and sequence are recognized and reported correctly. However, each time I press a button another button-number gets recognized.

Example with button 1 [D][esp_now:072]: mac: 6C.29.90.01.3D.37 (6), data: 80.A9.00.00.00.B2.5F.00.98.7E.B8 (11)

Event: { "event_type": "esphome.wizmote_action", "data": { "device_id": "ad01a7a7c8b0bd3d837e938cb62c7a51", "mac": "6c2990013d37", "button": "95", "sequence": "169" }, "origin": "LOCAL", "time_fired": "2022-07-16T16:47:38.274838+00:00", "context": { "id": "01G83YH492VTSQ8MSQWKYTQDE5", "parent_id": null, "user_id": null } }

Again button 1 [D][esp_now:072]: mac: 6C.29.90.01.3D.37 (6), data: 80.AA.00.00.00.11.58.71.25.CA.01 (11)

Event: { "event_type": "esphome.wizmote_action", "data": { "device_id": "ad01a7a7c8b0bd3d837e938cb62c7a51", "mac": "6c2990013d37", "button": "88", "sequence": "170" }, "origin": "LOCAL", "time_fired": "2022-07-16T16:48:19.735450+00:00", "context": { "id": "01G83YJCRQHHSYAKXBN4TJ0QV2", "parent_id": null, "user_id": null } }

Any help would be highly appreciated.

krakowski commented 1 year ago

I ran into the same issue. Bought two remotes from a local shop, which seem to be used (one had already batteries inserted). My guess is they both have been paired using the App and transmit encrypted data from this point on.

I pressed button 1 repeatedly and each time different data was logged inside ESPHome.

program  seq[0]   seq[1]   seq[2]   seq[3]   byte5    button   byte8    byte9    byte10   byte11
10000000 10100100 00000000 00000000 00000000 00110111 11010000 11000000 00010101 10001011 11000101
10000000 10100101 00000000 00000000 00000000 00111110 11100000 01110110 10000001 11010111 00000111
10000000 10100110 00000000 00000000 00000000 01111111 01011001 01110100 10111101 01001010 01101111
10000000 10100111 00000000 00000000 00000000 11100000 10011110 11010001 10000010 00101111 11101000
10000000 10101000 00000000 00000000 00000000 11100101 10011101 00010100 01101100 01111111 11001010

In my case the broadcast data starts with 0x80 opposed to the comment inside wizmote.h stating it can only be 0x91 or 0x81. Also, the data length is 11 bytes instead of 13. Resetting the remotes internal memory could help, but I couldn't find any way to do this.

@jesserockz Have you experienced this behavior? I would love to use those remotes for some home automations, but can only control a single action (based on the device MAC) at the moment.

Alternatively, I could try to write a custom firmware for the ESP inside the remote (TX, RX and GND are accessible), making it a "dumb" broadcasting device without the pairing functionality.

Edit

Managed to set the chip into flash mode and connect to it using esptool.

esptool.py v4.6.2
Found 1 serial ports
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... Unsupported detection protocol, switching and trying again...
Connecting...
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: bc:dd:c2:xx:xx:xx
Uploading stub...
Running stub...
Stub running...
Manufacturer: 68
Device: 4015
Detected flash size: 2MB

Edit 2

I managed to get a custom firmware running on the remote. There's one important aspect to note here. The ESP chip is only powered on during a keypress, which is quite confusing, since you have to short IO0 + GND AND also press a key so the chip boots. Looks like this is how the manufacturer implemented "deep sleep".

Receiving ESPNow packets from the second (non-modified) remote on the first (modified) remote works fine, but broadcasting doesn't seem to work. The esphome component doesn't print anything, although the send-callback is called with a status of 0 (success). Also tried enumerating all wifi channels. Still, no messages received on the esphome side (while the non-modified remote's messages are received). Here's my sketch:

uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

typedef struct broadcast_message {
  uint8_t button;
} broadcast_message;

broadcast_message broadcast_data;

void on_data_sent(uint8_t *mac_addr, uint8_t sendStatus) {
  Serial.print("Last Packet Send Status: ");
  if (sendStatus == 0){
    Serial.println("Delivery success");
  }
  else{
    Serial.println("Delivery fail");
  }
}

void setup() {
  // Initialize Serial communication
  Serial.begin(115200);

  // Set device as a Wi-Fi Station
  if (WiFi.mode(WIFI_STA) != true) {
    Serial.println("setting Wi-Fi mode failed");
    return;
  };

  // Initialize ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("initializing ESP-NOW failed");
    return;
  }

  // Set this device's role to CONTROLLER
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_send_cb(on_data_sent);

  // Register peer
  if (esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 0, NULL, 0)  != 0) {
    Serial.println("adding peer failed");
    return;
  }

  // Send ESPNow message
  broadcast_data.button = 2;
  if (esp_now_send(broadcastAddress, (uint8_t *) &broadcast_data, sizeof(broadcast_data)) != 0) {
    Serial.println("sending message failed");
    return;
  };  
}

void loop() {}

Edit 3

Turns out setting the channel number using esp_now_add_peer doesn't actually change the Wi-Fi channel. Put my network card in monitor mode and saw that the packets were sent successfully on channel 1 although I changed it to a different value inside esp_now_add_peer. Calling wifi_set_channel with the right channel number fixed this problem and the ESPHome node is showing the received (unencrypted) broadcast data :slightly_smiling_face:

[15:23:29][D][esp_now:071]: mac: BC.DD.C2.XX.XX.XX (6), data: 02
kb1sph commented 1 year ago

Hey everyone,

I thought I would comment on this after finding it over two years after my original post that was apparently copied for this code.

https://forum.arduino.cc/t/wizmote/700548

To start with, my code was just preliminary and I was still trying to figure things out. That being said, here is some additional info.

Byte 9, I had it labeled as always 100, this is not the case. For some reason my initial remote was doing just 100 many times in a row, later I found that it does change between seventy something and around 100. I have no idea what this byte is actually for.

As far as things changing on each button press for the button byte, I have used 4 different remotes, all were paired previously with bulbs through the app first, I'm not sure if that makes a difference, and all of them send the exact same data for the bytes that don't change and the first byte (0) has always been 129 or 145. Perhaps this is different for remotes released in different regions?

Also, for the power to stay on while your program is running, pin 16 is connected through a transistor to the voltage regulator's enable pin. Set pin 16 to HIGH immediately upon startup and then back to LOW to turn the remote off and save power.

As for power, I have also noticed that cheap batteries will cause the microcontroller to have issues and overhear (maybe stuck in a loop with brownout detection?) and the best batteries I have used are the Duracell Optimum.

Now, for the decoding, here's a little code for reference that has worked with every remote I have used.

#define REMOTE_TYPE_UNKNOWN         0
#define REMOTE_NAME_UNKNOWN         "Unknown"
#define REMOTE_TYPE_CUSTOM      1       // In case you want to identify custom remotes
#define REMOTE_NAME_CUSTOM      "Custom"    // with your own data structure
#define REMOTE_TYPE_PHILLIPS_WIZ    2
#define REMOTE_NAME_PHILLIPS_WIZ    "Phillips WizMote"
unsigned long lastsequence = 0;

void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
    char mac[18];
    char btn[13];
    snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0],
            mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
    unsigned long sequence = 0;
    int RType = RemoteType(data, data_len);
    if (RType == REMOTE_TYPE_UNKNOWN) {
        Serial.println("Unknown Remote Detected - Ignoring Data!");
        Serial.printf("Data Length: %d\n", data_len);
        for (size_t i = 0; i < data_len; ++i) {
            Serial.printf("data[%d] = %d\n", i, data[i]);
        }
        return;
    } else if (RType == REMOTE_TYPE_PHILLIPS_WIZ) {
        sequence = (unsigned long) data[4] << 24 | (unsigned long) data[3] << 16
                | (unsigned long) data[2] << 8 | (unsigned long) data[1];
        strcpy(btn, ByteToString(data[6]).c_str());
    }
    //  If data with same sequence number has been sent more than once, ignore it.
    //  This allows remotes to send multiple times to ensure delivery without
    //  processing the data more than once.
    if (sequence == lastsequence) {
        Serial.println("Duplicate sequence received.");
        return;
    }
        ButtonPressed(mac, btn);
    }
    lastsequence = sequence;
}

int RemoteType(const uint8_t *data, int data_len) {
    if (data_len == 13 && (data[0] == 129 || data[0] == 145) && data[5] == 32 && data[7] == 1) {
        // Remote identified as Phillips WizMote
        return 2;
    //} else if (if statement for custom remote) {
    //  return 1
    //}
    } else {
        return 0;
    }
}

void ButtonPressed(char *mac, char *btn) {
    // Your code to run when a button is pressed
}

Keep in mind this was written for arduino and for my specific needs in my program. Re-write as necessary for your own purposes.

Hopefully I didn't forget anything there as I copied my existing code and edited (deleted a lot) that wasn't necessary for the example. And, I hope this helps others to write more programs that can decode the WizMote. I'm sure there could be improvements to my code as I'm not an expert. I am open to suggestions.

krakowski commented 1 year ago

Hi @kb1sph,

Thanks for your input on this!

Also, for the power to stay on while your program is running, pin 16 is connected through a transistor to the voltage regulator's enable pin. Set pin 16 to HIGH immediately upon startup and then back to LOW to turn the remote off and save power.

This information is pure gold for me :slightly_smiling_face: I wondered why my custom program was only running during a button press. This will also enable me to implement the detection of long button presses.

As for power, I have also noticed that cheap batteries will cause the microcontroller to have issues and overhear (maybe stuck in a loop with brownout detection?) and the best batteries I have used are the Duracell Optimum.

I also encountered the same problem, thinking that my code ran into a loop because the remote's LED stayed on although I released the button. After some time I changed the batteries and everything was fine again. Using my custom firmware I only send the sequence number ( 4 bytes stored inside EEPROM ) as well as the button number ( 1 byte ) read from the PCA6416A chip (https://www.nxp.com/docs/en/data-sheet/PCA6416A.pdf) conntected via I²S. Using your input I can now try to add an additional byte for long button presses (true/false).

One thing I also noticed using wireshark in monitor mode is, that the remote sends out 12 packets on each wifi channel. I implemented my code so that it only sends one packet on one channel hoping that this will increase battery life.

Once I clean up my code, I will push it and post a link to the repository here for anyone interested in this.

krakowski commented 1 year ago

Hi,

I uploaded my firmware source code. You can find it at : https://github.com/krakowski/wizmod

If anyone is interested in improvements, please feel free to open a PR.

kb1sph commented 11 months ago

One thing I also noticed using wireshark in monitor mode is, that the remote sends out 12 packets on each wifi channel. I implemented my code so that it only sends one packet on one channel hoping that this will increase battery life.

Interesting. I have not played with wireshark with wireless. Perhaps this is a feature of the newer remotes? In my testing, with one of the first remotes that came out, I had to have the receiving chip on channel 1, no other channels would work. I was not able to connect to my router as well as receive ESP-Now signals on the same channel as the router, which is supposed to be possible as long as you are set to WIFI_MODE_APSTA, because the remote was only sending on channel 1. I'll have to check one of my newer remotes.

I'll have to look into how to use wireshark with wireless. Any pointers on this?

kb1sph commented 11 months ago

Also, yours has a PCA6416A??? Mine had a 74HC165A, which meant they had to put the sleep button on a gpio off of the ESP chip. It seems there are multiple versions even though they look pretty much the same. I am now wondering about my newer remote. I have 3 older remotes and one newer one. The older remotes had kind of a glossy finish to the shell while the newer one has a matte finish. Which one do you have?

Here is a copy of a crude, basic program I wrote for the WizMote which also allowed holding multiple buttons, including the sleep button which is not on the 74HC165A if anyone has the older remotes.

/*  NOTES FOR FLASHING!!!!!!!!
 *   
 *   WizMote uses an ESP8266 (ESP-WROOM-02D) with only 2MB of flash.
 *   Setting the flash size higher will cause the sequence to not be written to EEPROM.
 *   (This was the original first generation remotes, it appears things may have changed, so I can't guarantee this)
*/

#include <ESP8266WiFi.h>
#include <espnow.h>
#include <EEPROM.h>

// Added this and the associated code below, which I ran on the first write, to clear whatever was store in
// the eeprom from the factory as I did not attempt to read and decode what the factory programming stores where.
#define RESET_EEPROM false

int shift = 13;                                                           // Define Connections to 74HC165
int dataIn = 5;
int clockIn = 4;

byte buttonshift;
int buttonsleep;

unsigned long loopstart = 0;
unsigned long loopdelay = 25;                                            // Delay in between repeating signal
int buttonrepeat = 10;                                                     // Number of times to repeat signal
int randomnumber;

uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};        // Broadcast to all devices

typedef struct wizstructure {                                             // Data to send by ESP-Now
  byte program;                                                           // Seems to always be set to 145 when power button is pressed and 129
                                                                          // for any other button which suggests it might be used in the programming
                                                                          // sequence for bulbs which make you press the power button
  byte seq[4];                                                            // Incremental number sent each time a button is pressed. This is done in
                                                                          // order to prevent cloning the signal and and making sure each button press
                                                                          // is uniquely identified. It obviously does not defeat reverse engineering. :)
  byte byte6 = 32;                                                        // Unknown, but this seems to always have a value of 32
  byte button = 0;                                                        // Identifies which button is being pressed
  byte byte8 = 1;                                                         // Unknown, but this seems to always have a value of 1
  byte byte9 = 100;                                                       // Unkown. Initial testing on my oldest remote had this as always 100,
  byte byte10;                                                               // on newer remotes it can vary.
  byte byte11;
  byte byte12;
  byte byte13;
} wizstructure;
wizstructure Wiz;

void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {                  // Callback function after data is sent
  Serial.print("Last Packet Send Status: ");
  if (sendStatus == 0) {
    EEPROM.commit();
    Serial.println("Delivery success");
  }
  else {
    Serial.println("Delivery fail");
  }
}

uint8_t shiftIn165(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { // Custom shiftIn because the standard arduino function has the LOW and HIGH backwards for 74HC165A
  uint8_t value = 0;
  uint8_t i;

  for (i = 0; i < 8; ++i) {
    digitalWrite(clockPin, LOW);
    if (bitOrder == LSBFIRST) {
      value |= digitalRead(dataPin) << i;
    }
    else {
      value |= digitalRead(dataPin) << (7 - i);
    }
    digitalWrite(clockPin, HIGH);
  }
  return value;
}

void readbuttons() {
  digitalWrite(shift, LOW);                                               // Write pulses to shift Data
  delayMicroseconds(5);
  digitalWrite(shift, HIGH);
  delayMicroseconds(5);
  buttonshift = ~shiftIn165(dataIn, clockIn, LSBFIRST);                   // Read shift register inputs and flip bits to make it easier to understand
  buttonsleep = ~(digitalRead(14) >> 0) & 1;                              // Read sleep button state

  Wiz.program = 129;                                                      // Default value if On button is not being pressed
  switch (buttonshift) {                                                // Check for other buttons pressed and store the value in the Wiz structure
    case 64:                // 01000000
      Wiz.button = 1;       // On
      Wiz.program = 145;    // Program?
      break;
    case 128:               // 10000000
      Wiz.button = 2;       // Off
      break;
    case 16:                // 00010000
      Wiz.button = 16;      // 1
      break;
    case 32:                // 00100000
      Wiz.button = 17;      // 2
      break;
    case 4:                 // 00000100
      Wiz.button = 18;      // 3
      break;
    case 8:                 // 00001000
      Wiz.button = 19;      // 4
      break;
    case 1:                 // 00000001
      Wiz.button = 8;       // Dim
      break;
    case 2:                 // 00000010
      Wiz.button = 9;       // Bright
      break;
    case 0:                 // None of the previous detected, most likely sleep is pressed as it is on a separate input on the MCU.
      Wiz.button = 0;
      break;
    default:
      if (buttonshift > 128) {
        Wiz.button = 2;
      } else {
        Wiz.button = buttonshift + 128;
      }
  }
  if (buttonsleep && Wiz.button == 0) {                                                      // Determine if sleep is pressed before anything else as it is on GPIO 14 and not the shift register
    Wiz.button = Wiz.button + 3;
  } else if (buttonsleep && Wiz.button > 0) {
    Wiz.button = Wiz.button + 13;
  }
}

void setup() {
  digitalWrite(16, HIGH);                                                 // Pin state needed to keep voltage regulator on
  pinMode(16, OUTPUT);                                                    // Turn on output to voltage regulator to keep it in while the program is running
  pinMode(14, INPUT);                                                     // Sleep button input (because there are 9 buttons and 8 inputs on shift register)
  pinMode(shift, OUTPUT);                                                 // Shift pin for 74HC165A
  pinMode(clockIn, OUTPUT);                                               // Clock Pin for 74HC165A
  pinMode(dataIn, INPUT);                                                 // Data Pin for 74HC165A

  readbuttons();                                                          // Read buttons on setup to get a quick reading before the rest of setup.
                                                                                   // This helps get the button pressed right away so that it is not lost if you
                                                                                   // let go of the button while it is still going through the setup.

  Serial.begin(74880);
  EEPROM.begin(512);

  if ( RESET_EEPROM ) {
    for (int i = 0; i < 512; i++) {
      EEPROM.write(i, 0);
    }
    EEPROM.commit();
    delay(500);
  }

  WiFi.mode(WIFI_STA);                                                    // Initialize ESP-Now
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);                         // Set ESP-Now mode
  esp_now_register_send_cb(OnDataSent);                                   // Set callback function for data sent

  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);     // Register slaves/peers
}

void loop() {
  digitalWrite(16, HIGH);                                                 // I duplicated this in the loop in case you were holding the
                                                                                       // bright or dim buttons as the end of the loop shuts it off.
  randomSeed(analogRead(0));
  unsigned long sequence = (unsigned long)EEPROM.read(0) << 24
                           | (unsigned long)EEPROM.read(1) << 16
                           | (unsigned long)EEPROM.read(2) << 8
                           | (unsigned long)EEPROM.read(3);
  Serial.print("EEPROM Sequence: ");
  Serial.println(sequence);
  if (sequence == 4294967295) {
    sequence = 1;
  }
  else {
    sequence++;
  }
  EEPROM.write(0, (sequence >> 24));
  EEPROM.write(1, (sequence >> 16));
  EEPROM.write(2, (sequence >> 8));
  EEPROM.write(3, (sequence));
  Wiz.seq[3] = (sequence >> 24);
  Wiz.seq[2] = (sequence >> 16);
  Wiz.seq[1] = (sequence >> 8);
  Wiz.seq[0] = (sequence);
  Wiz.byte10 = random(255);    // This was for testing because these bytes seemed random
  Wiz.byte11 = random(255);
  Wiz.byte12 = random(255);
  Wiz.byte13 = random(255);

  uint8_t i;
  for (i = 0; i < buttonrepeat; ++i) {
    esp_now_send(broadcastAddress, (uint8_t *) &Wiz, sizeof(Wiz));        // Send data to slaves
    delay(loopdelay);
  }
  readbuttons();
  digitalWrite(16, LOW);                                                  // Turn off voltage regulator to save battery power
  if (Wiz.button < 8 || Wiz.button > 9) {                                 // If holding + or - the loop will continue until released and then power off
    while (1);                                                            // If other buttons are being held, stop loop and power off once released
  }
}

Keep in mind, I am far from an expert coder and just like to play around with things. I'm sure there are some things in this that I just wasn't understanding, some things that could be improved, or even things that have changed over time with the remotes changing.

A note on making a "universal program" for the remotes...

It looks like the newer one uses i2c, is that correct? Perhaps upon bootup we could check for an i2c device and run code accordingly and if it's not detected then run the code for the 74HC165?

kb1sph commented 11 months ago

Hi,

I uploaded my firmware source code. You can find it at : https://github.com/krakowski/wizmod

If anyone is interested in improvements, please feel free to open a PR.

Just looking at your code for a moment... Am I correct in that you only read port 0 inputs? If so, there are 8 inputs, but 9 buttons, are there not? Of course, I could be missing something because I am tired and on meds for some neck pain right now. LOL

krakowski commented 11 months ago

Hi,

regarding Wireshark, I just followed this documentation: https://wiki.wireshark.org/CaptureSetup/WLAN#linux

airmon-ng is pretty simple to use (requires root rights). After setting up wlan0 in monitor mode, you simply choose the mon0 interface inside Wireshark.

My remote has a matte finish and uses I2C. Also, the version printed on the PCB is V1.3, so there really seem to be different versions.

Yes, you are right, I only read port 0. Pressing the sleep button (you mean the button with the moon printed on it, right?) results in all bits set to 0, so I thought this was how they implemented this particular button. But you might be right. The button most likely is connected to one of the pins of port 1. I didn't use this button, so I didn't really bother me. Hope your neck pain gets better 😄

kb1sph commented 11 months ago

Yes, I meant the moon button. It is meant as a sleep mode for the lights, it dims them lower than you can with the normal dim button. You can also set it for circadian rythm and it will slowly dim at night and brighter from a soft white to bright white in the morning.

Hmmm, I haven't opened my older remote up recently to see if there's a version number printed on it, but I would assume they either didn't print one or that it's going to be the 1.0 version.

Let me know if you read port 1 and get a result for the extra button vs it being connected to a gpio pin like the older ones. I think I'm going to have to open mine up and see what the internal differences are now.

Did the pin 16 still work on your newer remote to keep it on?

kb1sph commented 11 months ago

Ok, so, I opened up my newest remote, which has more of a matte finish, but the exact same labeling as the older ones. The board in side is the exact same thing. It appears that maybe they switched the case first, then updated the circuit board later? Where did you get your remote from? Mine have all been from Home Depot. Perhaps they have older stock still.

20230923_143132 20230923_143100

krakowski commented 11 months ago

Hey,

thanks for your pictures. We definitely have different versions of the remote (my PCB color is blue).

Did the pin 16 still work on your newer remote to keep it on?

Yes, pulling it HIGH keeps the ESP chip on until I pull it LOW again.

Let me know if you read port 1 and get a result for the extra button

I didn't flash the remote but measured port 1 pin 0 against D9 (sleep button). My multimeter shows they are connected.

Where did you get your remote from? Mine have all been from Home Depot.

From OBI (one of the German "Home Depots" :smile:). Maybe PHILIPS sells different versions based on region. This is how my PCB looks like. Also, there seems to be a date written on the PCB 2019.9.9. Looks like it's 4 years old.

front back

kb1sph commented 11 months ago

When I get a moment, I'll have to take a picture of the button side. I didn't think to do that because I was just showing the chip differences. It might have a date. It's not very legible in the picture, but mine just has some seemingly random numbers with V00 at the end on the chip side. None of it appears to be in the same format as your date. I'm thinking yours is probably the newer design and the Home Depot here probably has a back stock in their warehouses of the older ones. Home Depot was one of the first companies in the US to carry the Phillips Wiz line of products.

It appears that you have a different regulator as well. Yours is 8 pin while mine is 6 pin.

kueblc commented 10 months ago

Does anyone have a firmware image from a device with this issue?

kueblc commented 7 months ago

I worked out the encryption and authentication schemes used for the WizMotes, both new and old. I could turn this into a PR if there is interest. I'd like to get some input on a few points first.

Inevitably, key material is needed in order to encrypt/decrypt or sign/verify. There's a couple of ways about this.

The key is stored on the WizMote and anything it is paired with. For now, it can be obtained by using esptool and a USB to serial adapter to read the flash memory off the device. The WizMotes I have seen are very easy to open and there's already clearly labeled programming pins on the board. Pros: offline, no legal complications. Cons: requires some technical skill and equipment, opens device, they may encrypt the flash in the future, need to manually input the key.

For some devices, like @drbiosignals newer WizMote, the key is generated deterministically. However, doing this requires a salt, which is not easily obtainable, and may not be distributable. Pros: offline, no setup or intervention needed by the user. Cons: potential legal complications, does not work on older WizMotes.

There may be a third option, but it probably is not a realistic one due to legal complications. As far as the theory goes, we could emulate adding a new Wiz light bulb, tricking another light bulb (or even the cloud) into handing out the keys. The process would require reimplementing more Wiz IP than anything else here, including an SSL certificate. Pros: no user intervention, works on all devices. Cons: legal, requires access to cloud or at least one real Wiz light.

So the first option is the least legally hazardous, works on all devices, but is kind of a pain. If I went with this, the next question is, what's the best way to hand the key off to wizmote-esphome? Build time option? Uploaded at runtime?

And finally, is there a use case for authentication? It makes sense to solve the encryption as it's not useful at all if it can't be deciphered. However I am not sure how practically concerned we are that it is authenticated. It is trivial to bypass, and transmission errors would be caught by mechanisms on lower levels.

Thanks for your thoughts.

sweetpi commented 5 months ago

@kueblc I've the blue PCB with the same issue. I will send you my firmware. It would be nice if you could share your knowledge about the authentication / encryption or make a PR and how to obtain the key from the image.

Thanks a lot.

nicholas-gh commented 1 month ago

Did the pin 16 still work on your newer remote to keep it on?

My remote setting pin 16 HIGH does not keep it on (I also tried LOW, just in case...)

Holding a button keeps it on and allows my program to execute; letting go of the button the LED goes dark a moment later and according to serial output my program stops too.

I've tried setting pins 0 to 20 to HIGH in case this worked, and then I could bisect to find the pin, but the power still drops. Maybe before all the pins are set, seems unlikely as I'd expect them to loop pretty fast, but serial output is confused since maybe setting random pins high interferes with TX... I'll do them one at a time in a series of tests...

EDIT: I've now tried 13 to 29, I see the serial output, but the LED and power still drops after:

  for (a = 13; a < 30; a++)
  {
    printf("%d\n", a);
    pinMode(a, OUTPUT);
    digitalWrite(a, HIGH);
  }

16 seems to normally be a WAKE pin for esp8266, so I'm surprised my remote doesn't stay on.

This is the remote:

Screenshot 2024-07-26 at 8 40 18 PM
nicholas-gh commented 2 weeks ago

I got another remote. Which by eye looks the same components and layout. But the colour and markings are different. The esp tin is older.

On this one, pin 16 DOES control the power, which is great news.

image

image