I did a calibration test as suggested and also read the documentation a bit more thoroughly.
First I changed the sketch to take a reading every 5 minutes and then go in to deep sleep to minimise the self heating of the chip.
#define uS_TO_S_FACTOR 1000000 // Conversion factor for micro seconds to seconds
unsigned long sleepyTime = 300; // Sleep time in seconds
void setup() {
// Configure the serial port
Serial.begin(115200);
delay(1000);
// Read the temperature
float temperature = temperatureRead();
Serial.printf("Temp onBoard = %.2f °C\n", temperature);
// Configure the wake up source and time.
esp_sleep_enable_timer_wakeup(sleepyTime * uS_TO_S_FACTOR);
// Enter hibernation
Serial.println("Going to sleep now\n");
delay(1000);
Serial.flush();
esp_deep_sleep_start();
}
void loop() {}
The technical reference here [section 39.3] gives a formula to convert the sensor reading to degrees Celsius.
I can't see how to set the offset or what its default value might be so I worked the number for all possible offset values to check if the values were actually raw. Results below.
Sensor Output is the value returned by temperatureRead(), External Temp is what I measured in the freezer, the fridge and at ambient. The column shaded blue is the closest. It still pretty far from the truth, but it has the signs right. Obviously, the numbers returned by temperatureRead() aren't simply raw.
To check if the numbers make any sense at all, I plotted one against the other and get a straight line. The result gives me some hope.
Multiplying the readings by 1.0465 and adding 14.474 aligns the two extremes.
So with careful calibration, I seem to have a solution, but it all seems very unnecessary.
Looking at the ESP32 code, I appear to be using the correct function, but I can't find the underlying implementation to see if the bug lies there.
Update 01/01/2024:
I posted a query on the Seeed Studio forum. The full conversation may be found here.
In summary, it looks as if proper support for the internal temperature sensor has not been added yet. There are potential fixes via library hacks, but that's all too much for me.
As for my way forward prior to full sensor support being added added, I don't want the permanently add an external sensor because I'm trying to design a Thing that works for as long a possible from a button cell. So I'll temporarily add an external sensor, BME280, to calibrate the internal sensor.