Two bugs, and a third waiting to happen. I did nearly this exact thing on a test rig years ago.
1. On the slave, each Wire.write() inside onRequest on AVR replaces the buffer instead of adding to it in some library versions, and the order of evaluation in (Wire.read() << 8) | Wire.read() on the master isn’t defined in C++, so the bytes can come out swapped.
2. The stray single byte shifts everything if the counts ever disagree.
Do it with one struct on both sides and one write:
struct __attribute__((packed)) Packet {
uint16_t m1, m2;
int16_t t_x100; // 23.47 C -> 2347, no float on the wire
uint8_t seq;
};
// slave
void onRequest() { Wire.write((uint8_t*)&pkt, sizeof(pkt)); }
// master
Packet p;
if (Wire.requestFrom(8, sizeof(p)) == sizeof(p))
Wire.readBytes((uint8_t*)&p, sizeof(p));
float t = p.t_x100 / 100.0;
Scaled integers avoid any float layout question if the slave ever becomes an ESP or an STM32. The seq byte tells you if you’re reading a stale packet. And on the ESP32 side, skip the key entirely if a reading is invalid instead of sending NaN, NaN isn’t valid JSON anyway.

