Hex-string to dec value

I am struggling with the hex-string to dec value in lambda function.
There are different values in the hex string where a few pairs make up these values.
The first one is in the 6D06 (3-6 character) where I need to read in reverse order by 2 character
so 6D06 needs to become 066D and then converted to the decimal value 1645
(next this needs to be divided by 100 resulting in 16.45 to be stored in a float)

std::string rawhex = format_hex_pretty((uint8_t *) x.c_str(), x.size()).c_str();
ESP_LOGD("raw_hex", "%s", rawhex.c_str());

rawhex.erase(std::remove(rawhex.begin(), rawhex.end(), '.'), rawhex.end());
ESP_LOGD("raw_hex_stripped", "%s", rawhex.c_str());

std::string temp_part_1 = rawhex.substr(4, 2);
std::string temp_part_2 = rawhex.substr(2, 2);
ESP_LOGD("temp_part_1", "%s", temp_part_1.c_str());
ESP_LOGD("temp_part_2", "%s", temp_part_2.c_str());

std::string temp_hex = temp_part_1 + temp_part_2; 
ESP_LOGD("temp_hex", "%s", temp_hex.c_str());

int i = std::atoi(temp_hex.c_str());

ESP_LOGD("temp_hex_i", "%i", i);

the output is like this:
[11:51:08][V][text_sensor:016]: ‘Ble reading data’: Received new state 3m\xaea\xd3
[11:51:08][D][text_sensor:067]: ‘Ble reading data’: Sending state ‘3m\xaea\xd3’
[11:51:08][D][raw_hex:159]: 33.6D.06.AE.07.D3.08.00.00.21.0E.12 (12)
[11:51:08][D][raw_hex_stripped:162]: 336D06AE07D3080000210E12 (12)
[11:51:08][D][temp_part_1:166]: 06
[11:51:08][D][temp_part_2:167]: 6D
[11:51:08][D][temp_hex:170]: 066D
[11:51:08][D][temp_hex_i:174]: 66

where hex: 066D → dec: 1645 and not 66

I tried atoi, stoi, QString, stoul and all other suggestions I found on forums regarding C++
the newer methods (like stoi and qstring) in C++ are giving errors that indicate there are not available for the compiler

What would be the best way to get the conversion working?

1 Like

Try this?

return (float)((int16_t)(x[2]<< 8) + x[1])/100;
1 Like

Thanks!
Works like a charm.

Would you mind explaining what happens with (x[2]<<8 + x[1])?

x[2] would be the 3th item in the returned value x, then I am confused about what x[1] does

i understand that you define a float with 16bit and that <<8 is a bitshift. Am trying to understand so I can learn something as I need more values from the hex string

Unsure that I can offer an eloquent response. My C++ isn’t so much “understanding” but, “I have a code snippet for that!” lol

With the provided sample I assumed we were working with a vector/array that we could index to extract the desired values. And since the example offered matched the sample, we found the source values at index 1 and index 2 since we begin indexing at 0. Flip them around, covert to float and divide by 100, voila!

Aha, OK now i understand
The initial hex value with the dots is a representation of the array received in value x and the <<8 moves that value to the end of the 16 bits and then we add the other to the first 8 bits

nice thinking, Thanks for the help!!
(kept me awake for some time…)

c_str() returns a \0 terminated char (byte) array of the string.
Being an array you can address the elments by their index.

x[2] = 06
x[1] = 6D

Assuming i is initialized with 0 we get:
bin: 0000 0000 0000 0000
hex: 0 0 0 0

Now you want to store these bytes in reverse order, this is achieved by x[2] << 8 since it writes 06 in the high byte of i which is:
bin: 0000 0110 0000 0000
hex: 0 6 0 0

Then +x[1] adds 6D which, given the nature of hex numbers, fits into the low byte of i.
bin: 0000 0110 0110 1101
hex: 0 6 6 D

Thanks for the explanation !!

Do you know how to output the char array in the log?
Would a loop be usable together with the size of the array like so:

for (size_t i = 0; i < x.size(); i++)
{
  ESP_LOGD("temp_hex", "%i", x[i]);
}

in my case I know the content is suppose to be hex, for other solution i might not exactly know what the content of the returned value x is

Beware this can quickly induce lag…

Taken from the ESPHome API Reference and massaged slighted

  void ESP_LOGD_HEX(std::vector<uint8_t> bytes, uint8_t separator) {
    std::string res;
    size_t len = bytes.size();
    char buf[5];
    for (size_t i = 0; i < len; i++) {
      if (i > 0) {
        res += separator;
      }
      sprintf(buf, "%02X", bytes[i]);
      res += buf;
    }
    ESP_LOGD("custom", "%s", res.c_str());
  }

// ESP_LOGD_HEX(x,':');
1 Like

The question rather is what you want to achieve.
raw_hex is already a string that can be printed as a whole. Why do you want to convert it to a char array and print each contained char?

No, just want to know its content. I am working on the transfer from data of a pool sensor to HA, where a few others provided a decoding of the hex. They didn’t use ESPHome yet so I thought to do that part and contribute a bit to the solution.

This was the last step to get it working. I wondered how one can tell what is being send back as value in x. Tried to print x and that crashed the esp module

ESPHome was new to me, so I tried a lot of stuff and some things I couldn’t get my mind around.
Also got an example like this esphome-components/examples/ble_client/delonghi.yaml at a453a0e2e395a261cd19f68801638bab9cb30000 · myhomeiot/esphome-components · GitHub

The raw hex is working for me and when I am a bit more enhanced in the c++ function I might be able to understand what is actually does instead of a high over understanding.