I2c NOOB QUESTION - Trying to get a MLX90614 IR Thermometer to talk to the Electric Imp

Hi all,
firstly, let me apologise for my complete lack of anything electronic &/or software.
This is my first foray into this area & I don’t have anyone in my circle of friends who can help me.
.
I want to get 2 x MLX90614 IR Thermometers to talk with the Electric Imp via the i2c12 & i2c89 ports (at least that’s what I think is possible).
.
For my first test, I followed Joel Wehr’s excellent tutorial on the Adafruit site regarding connecting a MAX31855 Thermocouple to the Electric Imp & have it communicate out via Xively & Twitter.
.
To my amazement; despite no understanding of how it works, not any previous knowledge of what Xively & Twitter were, I was able to get it going in a matter of minutes.
.
Buoyed by that success, I tried to adapt Joel Wehr’s project to the reference document I found on the Electric Imp main website regarding getting a “112 Temp Sensor” to talk to the i2c89 port.
.
I used another project on the bildr website to get a handle on the wiring of the MLX90614 for i2c.
.
Now that’s where my particular level of understanding ends.
.
I’ve uploaded the following DEVICE code:
.
`
// I’m trying to adapt the code from Joel Wehr
// regarding the MAX31855 thermocouple that posts to Xively & Twitter
// to work with a MLX90614 Infrared Thermometer
//
// To do that, I’m trying to adapt the
// Electric Imp Resources code
// regarding the i2c 112Temp Sensor
//
// Unfortunately, I’ve got no idea what I’m doing
// Hope I don’t fry anything

//Imp Pins for MLX90614 using i2c89
//
// imp 1 uassigned
// imp 2 unassigned
// imp 5 unassigned
// imp 7 unassigned
// imp 8 SCL
// imp 9 SDA

const TMP112 = 0x92;
const TEMP = 0x00;
const DEG_PER_COUNT = 0.0625;

// we need this for when we read a value
function twos_comp(value, mask) {
value = ~(value & mask) + 1;
return value & mask;
}

function read_c(i2c) {
local result = i2c.read(TMP112, format("%c", TEMP), 2);
local temp = (result[0] << 8) + result[1];

local mask = 0x0FFF;
local sign_mask = 0x0800;
local offset = 4;
temp = (temp >> offset) & mask;
if (temp & sign_mask) {
	temp = -1.0 * (twos_comp(temp, mask));
}

return temp * DEG_PER_COUNT;

}

tmp112 <- hardware.i2c89;
tmp112.configure(CLOCK_SPEED_50_KHZ);

server.log(read_c(tmp112));

// Send reading to Xively
agent.send(“Xively”, tmp112);

// Configure with the server
imp.configure(“MLX_90614_IR_Thermometer”, [], []);
. This is what I see in the log: <i>.2013-11-20 21:04:40 UTC+11: [Status] Device booting 2013-11-20 21:04:40 UTC+11: [Device] ERROR: the index '0' does not exist 2013-11-20 21:04:40 UTC+11: [Device] ERROR: at read_c:33 2013-11-20 21:04:40 UTC+11: [Device] ERROR: from main:49 2013-11-20 21:04:45 UTC+11: [Power State] Power state: online=>offline 2013-11-20 21:04:51 UTC+11: [Power State] Power state: offline=>online 2013-11-20 21:04:51 UTC+11: [Status] Device booting</i> . This is the code that I think the error is referring to (I've inserted from line 31 to 49 below here) .
function read_c(i2c) {
local result = i2c.read(TMP112, format("%c", TEMP), 2);
local temp = (result[0] << 8) + result[1];

local mask = 0x0FFF;
local sign_mask = 0x0800;
local offset = 4;
temp = (temp >> offset) & mask;
if (temp & sign_mask) {
	temp = -1.0 * (twos_comp(temp, mask));
}

return temp * DEG_PER_COUNT;

}

tmp112 <- hardware.i2c89;
tmp112.configure(CLOCK_SPEED_50_KHZ);

server.log(read_c(tmp112));
`
.
I really don’t know what the error refers to, nor how to fix it.
I was hoping that some kind person on here may be able to help me understand what the error is & how to rectify it.
.
Many thanks in advance,
duBe

You could try adding this line in your Device code

server.log(typeof(result ));

directly after your i2c.read and this would tell you what kind of data is being returned.

The error is indicating there is no zeroeth entry in the array.

If the type is array you could also add this for debugging

server.log(result.len());

Thanks mjkuwp94,
I’ve updated the DEVICE code to (what I think) you suggested:

`
// I’m trying to adapt the code from Joel Wehr
// regarding the MAX31855 thermocouple that posts to Xively & Twitter
// to work with a MLX90614 Infrared Thermometer
//
// To do that, I’m trying to adapt the
// Electric Imp Resources code
// regarding the i2c 112Temp Sensor
//
// Unfortunately, I’ve got no idea what I’m doing
// Hope I don’t fry anything

//Imp Pins for MLX90614 using i2c89
//
// imp 1 uassigned
// imp 2 unassigned
// imp 5 unassigned
// imp 7 unassigned
// imp 8 SCL
// imp 9 SDA

const TMP112 = 0x92;
const TEMP = 0x00;
const DEG_PER_COUNT = 0.0625;

// we need this for when we read a value
function twos_comp(value, mask) {
value = ~(value & mask) + 1;
return value & mask;
}

function read_c(i2c) {
local result = i2c.read(TMP112, format("%c", TEMP), 2);
// error check provided by mjkuwp94 to see what kind of data is being returned
server.log(typeof(result ));

local temp = (result[0] << 8) + result[1];
// array error check provided by mjkuwp94 to see what is in the array??
server.log(result.len());

local mask = 0x0FFF;
local sign_mask = 0x0800;
local offset = 4;
temp = (temp >> offset) & mask;
if (temp & sign_mask) {
	temp = -1.0 * (twos_comp(temp, mask));
}

return temp * DEG_PER_COUNT;

}

tmp112 <- hardware.i2c89;
tmp112.configure(CLOCK_SPEED_50_KHZ);

server.log(read_c(tmp112));

// Send reading to Xively
agent.send(“Xively”, tmp112);

// Configure with the server
imp.configure(“MLX_90614_IR_Thermometer”, [], []);
`

This is the logs I’m getting now:

2013-11-21 00:02:29 UTC+11: [Power State] Power state: online=>offline 2013-11-21 00:02:35 UTC+11: [Power State] Power state: offline=>online 2013-11-21 00:02:35 UTC+11: [Status] Device booting 2013-11-21 00:02:35 UTC+11: [Device] null 2013-11-21 00:02:35 UTC+11: [Device] ERROR: the index '0' does not exist 2013-11-21 00:02:35 UTC+11: [Device] ERROR: at read_c:36 2013-11-21 00:02:35 UTC+11: [Device] ERROR: from main:54

If I’m correct, ERROR: at read_c:36 relates to LINE 36??? which is:

local temp = (result[0] << 8) + result[1];

And running with that logic, ERROR: from main:54 relates to LINE 54?? which is:

server.log(read_c(tmp112));

I suspect the [Device] null relates to the:

server.log(typeof(result ));

And that would seem to indicate (to me at least) that there is no data being transmitted on the i2c lines???

If that’s the case, would that seem to indicate that I’ve mucked something up with the wiring on the MLX90614 IR Thermometer and it’s not talking on the i2c lines?

Or could it mean there’s something not right with the way I’ve tried to use the reference code?

Thanks again,
duBe

in my opinion, result[0] does not exist

There are line numbers in the IDE so guessing is not required. I think the main:54 is not what caused the error, it called the function that threw the error

your I2c read is returning null and the code is trying to read the 0th element of null which does not exist.

…edited…

perhaps back to basics of checking the wiring and metering the lines. I have not used this particular part so it is hard for me to know where to go next.

Thanks again mjkuwp94,
as I said, I am VERY uneducated with all things electronic & software, so I really didn’t know what the errors were telling me, so I just took a best guess that it was the line number. So; as the cut & paste to this forum doesn’t carry over the line numbers, I was trying to be as helpful as I could (not much I know, but trying at least).

There’s some learning right there for me, so been a good day already.

So; assuming the code is good (the people who wrote it know what they’re doing) & I’ve now checked the wiring a good few times again, then; as you suggest, I best get a good multi-meter & see if I can figure out what’s going on with the MLX90614.

Cheers,
duBe

Ok,
I know this is going to sound really dumb but I’ll say it anyway:

Noting that I know NOTHING about electronics & software, I tried to understand the MLX90614 data sheet (I know, I know).

Anyway, it occurred to me that perhaps the Code that Electric Imp supplied was only ever intended to work for one particular i2c thermometer & not this one that I’ve got.

So (again, this is going to be dumb) here’s some Arduino code that I’ve found that apparently will drive this MLX90614 IR Thermometer over the i2c lines on an Arduino.

Not sure if that gives any clue; I really appreciate any advice

`
#include <i2cmaster.h>

void setup(){
Serial.begin(9600);
Serial.println(“Setup…”);

i2c_init(); //Initialise the i2c bus
PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups

}

void loop(){
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;

i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x07);

// read
i2c_rep_start(dev+I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();

//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // zero out the data
int frac; // data past the decimal point

// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;

float celcius = tempData - 273.15;
float fahrenheit = (celcius*1.8) + 32;

Serial.print("Celcius: ");
Serial.println(celcius);

Serial.print("Fahrenheit: ");
Serial.println(fahrenheit);

delay(1000); // wait a second before printing again
}
`

Sorry again for being so dumb,
kind regards,
duBe

No need to apologize, its all about learning. I’m really glad to hear that someone actually followed my tutorial! :slight_smile: However, even though I’ll take credit for writing it up, most of that code was written by @beardedinventor, @mjkuwp94, and the others I mention in the tutorial. So, the credit for it all working so nicely goes to them, not me.

Thanks Joel,
Well I think @beardedinventor & @mjkuwp94 (and yourself) should be very proud to have produced such an easy to implement and incredibly useful tutorial that even a nufty like me can accomplish within a few minutes.

Thank you all.

Cheers,
duBe

So yeah, the first thing is getting the i2c address right; you can’t use the TMP112’s address to talk to it. From the above code it seems like the address you need is 0x5a<<1 (or 0xb4, in other words).

This bit of code:

` i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x07);

// read
i2c_rep_start(dev+I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();`

…would be replaced by:

// read local bytes=i2c.read(0xb4, 2); if (typeof(bytes)!= "string") { server.log("i2c read error: "+bytes); return; } local data_low = bytes[0]; local data_high = bytes[1];

Thanks Hugo,
I did manage to get 2 of these modules reporting on i2c12 and i2c89 and even (with @jwehr & @mjkuwp94 help) got them to report back to Xively on different channels. WooHoo!!!

And after a long-overdue sleep, I’ve come back and re-tested the temp readings and; although they aren’t exactly calibrated, they do appear to be reading “near enough” given an allowance.

Eg:

  1. An ice-brick from my -15° C freezer reads anywhere between -5°C to 0°C depending how close I hold it to the sensor (closer = more accurate).

  2. My iPhone temp app reports a room temp of 14° C (and it feels like that’s pretty spot on today) but the sensors read 21° C.

So based on the history of them both consistently reading about 7°C too high, could I just put in a -7°C “calibration” factor?

I’ve put in your suggested code amendment however it hasn’t changed the readings.

I was thinking I might be able to amend this line of code:
celcius_89 = tempData_89 - 273.15;
to read:
celcius_89 = tempData_89 - 280.15;

I’m not too sure if this is a good idea or not, what are your thoughts?

Thanks in advance,
duBe

Thanks Hugo,
I did try setting the address but (as my understanding of this is zero), I thought it was “0x5A” & when that didn’t work I put that aside till I found an answer.

Gotta confess, would never have worked out that “0x5A<<” equates to “0xB4” so thanks heaps for that.

Ok, so I’ve re-written the DEVICE code :

`
server.log(“Imp MLX90614 v0.02 Started”);

// i2c89 Interfact to MLX90614 Infrared Thermometer
// Imp Pins
// Pin 8 = SCL
// Pin 9 = SDA

// set the i2c clock speed.
// the MLX90614 can handle between 10kHz and 100kHz
hardware.i2c89.configure(CLOCK_SPEED_50_KHZ);

// read i2c
local bytes=i2c.read(0xb4, 2);
if (typeof(bytes)!= “string”) {
server.log("i2c read error: "+bytes);
return;
}
local data_low = bytes[0];
local data_high = bytes[1];

server.log("data_low is: "+data_low);
server.log("data_high is: "+data_high);

// gotta get the math conversion done here
// I don’t understand the original Arduino code
// so I’m gonna struggle converting it to Squirell which I don’t understand either

// once the conversion is done gotta send the resultant Celcius reading to Xively agent

imp.configure(“Imp IR Thermometer”, [], []);
`

but I get the following Log errors (I think it is saying that i2c is an array, so I don’t follow that at all):

013-11-22 09:49:51 UTC+11: [Status] Device booting 2013-11-22 09:49:51 UTC+11: [Device] Imp MLX90614 v0.02 Started 2013-11-22 09:49:51 UTC+11: [Device] ERROR: the index 'i2c' does not exist 2013-11-22 09:49:51 UTC+11: [Device] ERROR: at main:21 2013-11-22 09:49:56 UTC+11: [Power State] Power state: online=>offline 2013-11-22 09:50:02 UTC+11: [Power State] Power state: offline=>online

Any advice would be greatly appreciated,

Cheers,
duBe

I used “i2c” as shorthand there, replace it with the i2c you’re using, in this case hardware.i2c89

0x5c << 1 is 0x5c shifted left by one place, ie multipled by 2, which is 0xb4.

Thanks Hugo,
I did try:
"i2c89.read"
as I thought that what was needed but just came back with a similar error.

Now I know why:
“hardware.i2c89.read”

looking at it now, it makes perfect sense, thanks

Fixing pre 1980 VW’s I’m ok with but math, electronics & software is all NEW to me.
I’d be lying if I said I understand the explanation of the addressing but I’ll keep plugging away & hopefully get some sense of it in the future.

So, I updated the code & it came back with an error that I assumed had something to do with a sub-address not being present:

2013-11-22 10:35:47 UTC+11: [Device] ERROR: bad parameters to i2c.read(target,subaddress,size) 2013-11-22 10:35:47 UTC+11: [Device] ERROR: at main:21

So (taking a punt), I tried inserting a blank placeholder (not sure if that terminology is correct) for the sub-address (obviously as I don’t understand the addressing, I don’t know if it has a sub-address):

local bytes=hardware.i2c89.read(0xb4, "", 2);

And that seemed to make the code return something finally, although I suspect it’s erroneous, as both high & low are 255:

2013-11-22 10:35:58 UTC+11: [Status] Downloading new code 2013-11-22 10:35:58 UTC+11: [Device] Imp MLX90614 v0.02 Started 2013-11-22 10:35:58 UTC+11: [Device] data_low is: 255 2013-11-22 10:35:58 UTC+11: [Device] data_high is: 255 2013-11-22 10:35:58 UTC+11: [Status] Device configured to be "Imp IR Thermometer"

I’ve tried putting different temperature items in front of the sensor with no change in the readings returned.

Do you think this could be correct readings & all I need to do is work out the conversion math routine?
Or do I have another problem?

Thanks in advance,
duBe

Ok, so I downloaded the datasheet; you need to send a command to read the data - this was actually in your arduino example but I totally missed it!

Change your null string for subaddress to “\x07” and hopefully you’ll have more luck :slight_smile:

Wow!
Thanks HEAPS Hugo, that totally worked:

local bytes=hardware.i2c89.read(0xb4, "\\x07", 2);

This is what I get in the logs now:

2013-11-22 12:40:20 UTC+11: [Status] Downloading new code 2013-11-22 12:40:21 UTC+11: [Device] Imp MLX90614 v0.02 Started 2013-11-22 12:40:21 UTC+11: [Device] data_low is: 169 2013-11-22 12:40:21 UTC+11: [Device] data_high is: 57 2013-11-22 12:40:21 UTC+11: [Status] Device configured to be "Imp IR Thermometer"

I hope one day that I’ll understand that command to the subaddress as I would NEVER have gotten that. When I saw your suggestion, I honestly thought it was a typo & was meant to be 0x07 as that was in line with what I thought an addressing standard might have been.

So; aside from me not understanding anything much, I’m so happy that the Electric Imp is now communicating with the MLX90614 IR Thermometer finally.

Not sure you want this, but here’s the current (working) DEVICE code you fine people ( @beardedinventor , @mjkuwp94 , @jwehr & @Hugo ) have come up with for me:

`// Electric Imp with MLX90614 Infrared Thermometer using i2c
//
// This code has been cobbled together by the following AWESOME people
// @beardedinventor @mjkuwp94 @jwehr and @Hugo
//
// I really appreciate the time these people have taken to help me get this far

server.log(“Imp MLX90614 v0.02 Started”);

// i2c89 Interface to MLX90614 Infrared Thermometer
// Imp Pins
// Pin 8 = SCL
// Pin 9 = SDA

// set the i2c clock speed.
// the MLX90614 can handle between 10kHz and 100kHz
hardware.i2c89.configure(CLOCK_SPEED_50_KHZ);

// read i2c
local bytes=hardware.i2c89.read(0xb4, “\x07”, 2);
if (typeof(bytes)!= “string”) {
server.log("i2c read error: "+bytes);
return;
}
local data_low = bytes[0];
local data_high = bytes[1];

server.log("data_low is: "+data_low);
server.log("data_high is: "+data_high);

// gotta get the math conversion done here
// I don’t understand the original Arduino code
// so I’m gonna struggle converting it to Squirell which I don’t understand either

// once the conversion is done gotta send the resultant Celcius reading to Xively agent

imp.configure(“Imp IR Thermometer”, [], []);
`

Many thanks,
duBe

Just one other question if I might (completely different)
.
I’ve put in a “loop” (if that’s the correct terminology) to force the imp to check the temp every 10 seconds & report that to the server.log.

`
// read i2c
function getTemp() {

local bytes=hardware.i2c89.read(0xb4, “\x07”, 2);
if (typeof(bytes)!= “string”) {
server.log("i2c read error: "+bytes);
return;
}
local data_low = bytes[0];
local data_high = bytes[1];

server.log("data_low is: "+data_low);
server.log("data_high is: "+data_high);

imp.sleep(10); // sleep for 10 seconds
getTemp();

}
`

As best I understand it, that is correct?

Anyway, the imp is now displaying some very odd behaviour:
It takes a few spins through the loop, then goes offline, then online, then tries to take another reading, then goes offline, etc.

After a short time, the imp just stays offline & stops responding all together, forcing me to remove power then reapply power to get it working again.

2013-11-22 14:57:36 UTC+11: [Device] data_low is: 3 2013-11-22 14:57:36 UTC+11: [Device] data_high is: 58 2013-11-22 14:57:36 UTC+11: [Power State] Power state: online=>offline 2013-11-22 14:57:57 UTC+11: [Power State] Power state: offline=>online 2013-11-22 14:57:57 UTC+11: [Device] data_low is: 251 2013-11-22 14:57:57 UTC+11: [Device] data_high is: 57 2013-11-22 14:58:07 UTC+11: [Device] data_low is: 6 2013-11-22 14:58:07 UTC+11: [Device] data_high is: 58 2013-11-22 14:58:17 UTC+11: [Device] data_low is: 5 2013-11-22 14:58:17 UTC+11: [Device] data_high is: 58 2013-11-22 14:58:27 UTC+11: [Device] data_low is: 0 2013-11-22 14:58:27 UTC+11: [Device] data_high is: 58 2013-11-22 14:58:27 UTC+11: [Power State] Power state: online=>offline 2013-11-22 14:58:48 UTC+11: [Power State] Power state: offline=>online 2013-11-22 14:58:48 UTC+11: [Device] data_low is: 255 2013-11-22 14:59:18 UTC+11: [Power State] Power state: online=>offline

I thought maybe there’s something wrong with the USB power that’s coming off my mac, so I’ve plugged the imp into a wall-socket 5vdc pack but this persists.

Any assistance would be greatly appreciated.

Kind regards,
duBe

Further to this; by way of fault-finding, I reloaded the MAX31855 Thermocouple code onto this imp & it had no such problem.

So then I removed the “loop” amendments I made to this MLX90614 code as I assume it’s wrong, somehow causing the imp to crash.

I’ve reloaded the last working MLX90614 onto the imp & although it doesn’t “loop”, the “power state” is no longer appearing as a problem.

I’ll have to keep plugging away to better understand how to make the code recycle in a “loop”.

Cheers,
duBe

Ok,
done a bit more “learning” and I’m pleased to report that I’ve now resolved the “loop” problem & apart from some funky temperature readings (think it’s got to do with the conversion math for the sensor readings) the Imp is now reading the MLX90614 IR Thermometer sensor every 10 seconds & reporting that out to Xively & Twitter.

I’ve gotta say how very thankful I am to the following AWESOME people who have made this project possible:
@Hugo
@mjkuwp94
@beardedinventor
@jwehr

not only have these people put all this code & and associated tutorials together, they have displayed the patience of Solomon with me; I am so very thankful.

For those who are interested, here is the final DEVICE code that seems to work like I was hoping:

`
// Electric Imp with MLX90614 Infrared Thermometer using i2c
//
// This code has been cobbled together by the following AWESOME people
// @beardedinventor @mjkuwp94 @jwehr and @Hugo
//
// I really appreciate the time these people have taken to help me get this far

server.log(“Imp MLX90614 v0.02 Started”);

local celcius = null;

// i2c89 Interface to MLX90614 Infrared Thermometer
// Imp Pins
// Pin 8 = SCL
// Pin 9 = SDA

// set the i2c clock speed.
// the MLX90614 can handle between 10kHz and 100kHz
hardware.i2c89.configure(CLOCK_SPEED_50_KHZ);

// read i2c
function read_c() {
local bytes=hardware.i2c89.read(0xb4, “\x07”, 2);
if (typeof(bytes)!= “string”) {
server.log("i2c read error: "+bytes);
return;
}
local data_low = bytes[0];
local data_high = bytes[1];

server.log("data_low is: "+data_low);
server.log("data_high is: "+data_high);

// gotta get the math conversion done here
// I don't understand the original Arduino code
// & I have to convert it to Squirell which I don't understand either
// So what I've done here is just to completely reuse the Arduino Code
// Just replacing what doesn't work (like "double" "float" "int" with "local")

// This seems to work, except that the temperature readings don't seem to be at all accurate
// something wrong with the conversion I reckon:
// a -19deg c icepack reads 8deg c, a 60deg c piece of metal reads 33deg c
// but the room temp seems almost accurate, iphone says 21deg c which reads 24deg c

//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
local tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
local tempData = 0x0000; // zero out the data
//int frac; // data past the decimal point

// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;

celcius = tempData - 273.15;

// wakeup every 10 seconds and read temperature
imp.wakeup(10, read_c); 

server.log("The temperature is " +celcius +"C");

// Send reading to Xively
agent.send("Xively", celcius);

}

imp.configure(“Imp IR Thermometer”, [], []);
read_c();
`

I’m gonna keep plugging away at this to try to achieve more believable temperature readings & hopefully get two of these MLX90614 sensors talking on both i2c12 & i2c89 ports, then report them back to 2 separate Xively channels so that I can see both channels on @jwehr excellent Pitchfork App (well worth the $0.99 at the Apple AppStore).

Many thanks again,
duBe68

The algorithm you’re using appears to match the arduino one so that should be fine.

The temperature readings (posted in your logs above) do seem somewhat off - the high value should be a lot higher unless your targets are well below freezing!

I can’t see how this would affect things, but try reading 3 bytes (this will then get the PEC code, which we aren’t checking anyway) - ie change the 2 to a 3 in the i2c read.