FastCRC with Home Assistant

Hi

I've been building my home automation and being an electronics designer I wanted to make my own zigbee2mqtt devices. For this I'm using ptvo.info firmware which offers two way UART.

The problem is, that the data isn't transmitted correctly from the zigbee module to HA. The error in transmission is a lost byte which is not position dependent, it can be lost in any location of the string. Also, it's not possible to send a quote mark with the \" syntax, as the escape character is always added to the string. Due to this native json parsing is not possible. Or then my skills are not sufficient for this.

I thought to circumvent this by parsing the string with python and adding a CRC checksum to the string. I get the string ok, but the CRC is different than compared with online calculators.

The code is:

    zigbeeOutputString = "123456789";

    // Calculate CRC
    uint8_t crcArray[zigbeeOutputString.length() + 1];
    zigbeeOutputString.getBytes(crcArray, zigbeeOutputString.length() + 1);
    uint16_t crcValue = CRC16.modbus(crcArray, sizeof(crcArray));

  zigbeeOutputString += " ";

    zigbeeOutputString += itoa(crcValue, str, 10);
    zigbee_serial.print(zigbeeOutputString);
    zigbee_serial.print(" ");
    zigbee_serial.print(crcValue, HEX);
    zigbee_serial.write(0x0d);
    zigbee_serial.flush();
    zigbeeOutputString = "";

And the data received (when without errors) in Home Assistant:
"action": "123456789 23031 59F7"

crccalc.com gives 0x4B37 as the CRC when CRC16-MODBUS is selected. I also tried with CCITT and kermit variations of which other online crc calculation sites give same result as the crccalc.com, from which I assume they calculate it correctly. I've tried all FastCRC algorithm variations and none send the right checksum, so I'm making the assumption that my code has bugs in it. I just can't figure out what.

All ides and suggestions are most welcome!

Kind regards, Esa

Don't post snippets (Snippets R Us!)


what is str in there ? do you have enough space ?


with sizeof you are getting the trailing null char in your CRC calculation


consider this code

String zigbeeOutputString = "123456789";

// Function to calculate CRC16 for Modbus
uint16_t calculateCRC16(uint8_t *data, size_t length) {
  uint16_t crc = 0xFFFF;

  for (size_t i = 0; i < length; ++i) {
    crc ^= data[i];
    for (size_t j = 0; j < 8; ++j) {
      if (crc & 0x0001) {
        crc >>= 1;
        crc ^= 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }

  return crc;
}

void setup() {
  Serial.begin(115200);
  uint16_t crcValue = calculateCRC16(zigbeeOutputString.c_str(), zigbeeOutputString.length());
  Serial.print("CRC16: 0x");
  Serial.print(crcValue, HEX); // Print CRC16 value hex
  Serial.print(" / ");
  Serial.println(crcValue); // Print CRC16 value decimal

  zigbeeOutputString += " ";
  zigbeeOutputString += String(crcValue);

  Serial.println(zigbeeOutputString);
}

void loop() {}

it will print to the Serial monitor

CRC16: 0x4B37 / 19255
123456789 19255

you probably should not use the String class and there is no need for concatenation, just zigbee_serial.print() each element in sequence, you'll save RAM and CPU time.

Hi

I was amazed how fast this was replied to.

I got the CRC working with this. Thank you very much!

There was some build error with the crcValue line, but the following works:

    // Calculate CRC
    uint8_t crcArray[zigbeeOutputString.length() + 1];
    zigbeeOutputString.getBytes(crcArray, zigbeeOutputString.length() + 1);
    uint16_t crcValue = calculateCRC16(crcArray, zigbeeOutputString.length());

I can't code for s*** but if it works, I'm not going to fix it :D.

Kind regards, Esa

Glad it helped
Have fun

Yes by calling length you don’t get the trailing null char.

There is no reason to duplicate the string to calculate the CRC, just pass the underlying buffer c_str() to the CRC function.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.