Showing posts with label DS18B20. Show all posts
Showing posts with label DS18B20. Show all posts

29 Jan 2021

Sensing Temperature with a RaspberryPi - pt2

In my previous post I started a conversation around the details of sensing a temperature with a RaspberryPi. That post discussed using the cheapest temperature sensor available: a thermistor. Using a thermistor with an RPi is cheap, but not very straight-forward: an ADC is required, we need to communicate with that ADC (over SPI in my particular case), a voltage divider circuit is required to convert a varying resistance into a varying voltage, and we need some funky math in order to account for the sensor's non-linearity with respect to resistance versus temperature over a range of temperatures. Not to mention the further adjustments we need to make in order to account for the self-heating of the thermistor device itself.

However, learning how to work with one resistive sensor opens the door to working with a whole host of other resistive sensors (light sensors, pressure sensors, potentiometers, sliders, joysticks, etc). So while reading temperature in this way is challenging, the tricks learned along the way are useful in other common electronic designs as well.

My examples use a RaspberryPi specifically because I wanted to show an end-to-end example of reading an actual temperature with an actual SBC. From evaluating various temperature devices, choosing and buying one… all the way to connecting it to the RaspberryPi and reading the temperature in user-space. However, any of a large number of SBCs could be used. Although these posts are RaspberryPi-specific, many of the steps and concepts can be applied to a wide range of Linux-capable SBCs.

Continuing along with the discussion of reading a temperature with a RaspberryPi, this post will discuss a different class of temperature sensor.

Digital Thermometer

At the polar opposite end of the spectrum from the hard-to-work-with thermistor are a class of temperature-sensing devices I'm calling "digital thermometers". I've seen that phrase used in a couple places, but the term isn't universal.

Whereas simple devices, such as the thermistor, require you to add various other components to your design and perform a complicated conversion from resistance to temperature, a digital thermometer is usually wired directly to the RPi and all that you need to do is read a temperature value directly from the device itself. There are no hoops to jump through to account for self-heating, or 3rd-order transfer functions to implement to adjust for the non-linear relationship between changing resistance versus changing temperature, no extra components to add to your design, and no circuitry you need to figure out and measure to improve the accuracy of your calculation.

The digital thermometer handles all of these things itself and simply provides a temperature (or something that is easily translated into a temperature). Conceptually it's as if all the pieces that were discussed in the previous post (except for the inter-chip communication) were encapsulated together into the sensor (including some of the software that would have needed to be written for the RPi):


NOTE: I'm not trying to imply that digital thermometers are based on thermistors; in fact according to their datasheets they are not. But I'm trying to relate back to case of the thermistor to show how much more advanced these devices are.

Examples of digital thermometers include:

  • TMP102 from Sparkfun
  • Si7021 from Adafruit
  • TC72
  • DS18B20

There are dozens (or hundreds?) of digital thermometers from which to choose. Select the accuracy, the range of temperatures you want to measure, your favourite inter-IC communication bus, and you're mostly done. Many of these devices have come about thanks to the maker movement. Taking sophisticated ICs, putting them on breadboard-friendly break-out boards, and adding any required circuitry makes successful projects easier. In addition to the hardware, most of these devices also come with (mostly Python) libraries, just in case neither hardware nor software are your strong suits when working with electronics ;-)

TMP102

The TMP102 temperature break-out board from Sparkfun has the following characteristics:

  • a resolution of: 12 bits
  • a range of: -25°C to +85°C
  • an accuracy of: ±0.5°C
  • and communicates over: I2C

If you decide to forgo the Python library you'll need to know the format of the data you'll receive from the device. Simply refer to the datasheet and you'll find:


The upper-case Ds represent the value to the left of the decimal point, the lower-case ds represent the fractions. If a whole-number calculation of the device's temperature will suffice, simply take the first byte that is given and ignore the second.

Si7021

The Si7021 is an example of a digital thermometer from Adafruit. It's specs are:

  • configurable from 11-bit to 14-bit resolution
  • -10°C to +85°C
  • ±0.4°C
  • I2C

The Si7021 provides an example of a digital thermometer that doesn't, exactly, give you a temperature, but it gives you something (a "Temp_Code") that is easy to convert to a temperature:


TC72

I can't find any examples of the TC72 on a maker-friendly break-out board but there are generic break-out boards to which it could be attached.

  • 10-bit
  • -40°C to +85°C
  • ±2°C
  • SPI

Data format:


DS18B20

The DS18B20 is a very popular temperature-sensing device, and with good reason. In addition to its great specs, it is available both as a discrete component, as well as in a water-proof temperature-appropriate housing.


  • configurable 9-bit to 12-bit resolution
  • -55°C to +125°C
  • ±0.5°C accuracy
  • 1-wire communication protocol

It's data format is as follows, and is very similar to a 16-bit signed 2's complement representation:


Designing for Multiple Sensors

In many situations the goal is to put one temperature sensor in an area (e.g. to measure the temperature of a room). For these situations, hooking up one temperature sensor to one SBC and distributing one set of these in each area will suffice. However, in other situations, the goal is to distribute a lot of sensors in a small area (e.g. monitoring the supply and return temperatures of a multi-zone HVAC system). Hooking up 1 or 2 sensors via I2C or SPI to one RaspberryPi isn't too hard, but trying to connect a dozen or more devices on these same buses can be a challenge. Another option would be to use a dozen RaspberryPis with 1 or 2 sensors each, but that's getting silly.

The problem lies with how these buses were designed, and the assumptions that were used when designing them.

SPI

The SPI bus consists of 1 clock line and 2 data lines (one for each direction):

The specific slave device to which the master wants to talk is selected using a physical chip select line. When a design calls for multiple SPI devices, multiple chip select lines need to be used:

The above diagram shows a master with one SPI bus that has 3 chip selects on it. The standard RaspberryPi 40-pin expansion header has two SPI buses. The first SPI bus (SPI0) exposes 2 chip selects, and the second SPI bus (SPI1) exposes 3 chip selects.

Pins 19 and 21 are the 2 data lines for SPI0, pin 23 is the SPI0 clock pin, and pins 24 and 26 are the 2 chip selects for SPI0.

Pins 38 and 35 are the 2 data lines for SPI1, pin 40 is the SPI1 clock pin, and pins 12, 11, and 36 are the chip selects for SPI1.

All of the pins for SPI0 are readily available on the 40-pin header. The data lines and clock pins are available for SPI1 as well. However, the 3 chip selects for SPI1 are not the primary functions of those pins, so extra setup is required to set those chip select pins for SPI mode.

If you wanted to hook up more than 2 devices to the RaspberryPi's SPI0 bus you would need more chip select lines; the same is true for the Pi's SPI1 bus as well. Setting up more chip select lines requires some hardware work and tweaks to the driver software. It's possible, but it's getting complicated due to the nature of how the SPI bus works.

Another way to connect multiple devices to an SPI bus is as follows:

This is an example of connecting multiple SPI devices in a daisy-chain topography. One chip select always selects all devices at the same time, but the data from the first device travels to the next device down the chain, and so on, until the last device connects back to the master. This is the topology used for JTAG. In theory a large number of devices can be connected to one SBC using this topology. However, with this design it's not possible for the master to query any one device at a time, it must always clock enough times to get all the data from all the devices with each request. The slaves themselves must also support a pass-through mode which enables them to save up the received bits and send them along after they've put their own data on the data line.

In other words, this topology is also complicated and not always possible.

Whether you are using the first topology (multiple chip select lines) or have daisy-chained your devices together, there is no way for your software to know how you've wired everything together. Give 10 people the same two SPI devices to connect to the RaspberryPi's SPI0 bus and half of them will connect device A to chip-select 0 and the other half of them will connect device B to chip-select 0. Neither arrangement is wrong, but these differences need to be taken into account. As a result, SPI buses are not discoverable. There is no way for Linux to know, a-priori, the devices to which it is connected or how they've been wired up. There's no unique ID that can be sent to let Linux know exactly what's connected to where. Therefore, there's no way Linux can do all the work for you; you need to write some code for your specific arrangement, and therefore are responsible for interpreting the data you receive from each device. Plus this code needs to be flexible enough to allow the user to specify the wiring so your code knows where to look for its data.

I2C

With I2C there is 1 data line and 1 clock line:

Notice that there are no chip select lines. The master specifies the slave with which it wishes to communicate by providing an address as part of the message preamble. This has the added side-effect of reducing the data throughput rate since some part of every communication is taken up specifying an address. The original I2C spec specifies 7 bits to be used for these addresses; meaning there are only 128 unique address possibilities. With 1000s and 1000s of I2C devices on the market, you can be assured the possibility for address collisions is more than probable! This address isn't based on topology or related in any way to a device's position on the bus. This address is a number that is burned into the device, and when the device sees this number in the preamble of a message, it responds. Each I2C device has to know the address to which it is to respond. For many I2C devices an address is chosen by the manufacturer and simply burned into its circuitry. This address is specified in the device's datasheet. There is no central repository or authority dispensing these addresses, so manufacturers are free to use whatever address they want. Fancier I2C devices use from one to three external pins to allow the user to modify some part of the I2C address; the rest of the address is burned into the device. When the device is placed into its circuit these pins are either grounded or tied high to change the address; at which point their address becomes static. In recent years there have been new revisions of the I2C spec that allow for 10-bit addresses, but the adoption rate has been slow.

Therefore, trying to attach multiple of the exact same device to a RaspberryPi becomes tricky. If you're lucky you might be able to change 3 of the 7 address pins, giving you the ability to add up to 8 of the same device to each I2C bus your SBC exposes… but only if you're lucky and your specific device provides these address pins. Otherwise each I2C bus on your SBC can only accommodate up to 1 instance of a specific device if that device uses a fixed address.

The standard 40-pin expansion header on the RaspberryPi includes 1 I2C bus: I2C1. Pin 3 is the I2C1 data line, and pin 5 is the I2C1 clock pin.

This situation (regarding I2C device addressing) means that the I2C bus is not discoverable. You can't connect a random bunch of I2C devices to your SBC and have Linux magically know which devices you have connected, and therefore automatically know how to interpret the data it receives from those devices. Any address could conceivably be used by any number of non-related devices, and with devices where the user can modify parts of the address itself, those devices could have any of a range of addresses. Therefore when using I2C Linux can help you with the minutiae of sending and receiving individual data packets, but knowing which devices are in use and how to interpret their data is up to you.

1-Wire

As we've already seen, the DS18B20 is one of the simplest devices to use with the RaspberryPi; wire it up, and read its temperature. No extra circuitry required, no fancy conversions. But the fact it uses the 1-wire protocol gives us a couple additional benefits as well.

As part of the 1-wire protocol, any device that uses the 1-wire protocol must have a 64-bit unique serial ID (address) burned into it from the factory. The first 8-bits of this 64-bit number identify the device class, which is centrally administered in order to avoid address collisions. A centrally-administered database of device classes means that OSes, like Linux, can uniquely identify what type of device is connected, and can therefore know how to present its data. The DS18B20's class ID is 0x28, therefore any time Linux detects a 0x28 device connected to it via 1-wire, it knows this is a DS18B20 and can dynamically create a file in sysfs that presents user-space with a simple temperature reading. 1-wire buses are discoverable.

The other advantage of the 1-wire protocol (made possible as a consequence of the unique 64-bit number burned into every device at the factory) is its ability to enumerate all such devices attached to a single bus. Due to the low-speed nature of the bus, and various other electrical properties, 100s (if not 1000s) of devices can be connected together on 1 GPIO pin; all uniquely addressable, and all able to report their unique temperature reading to the user.

Multiple Sensors Conclusion

If you want to connect only one sensor to your device, any sensor using any bus will do. Once you get between 2 and 8, you'll probably want to drop SPI and try either I2C (if your device has 3 address pins) or 1-wire. But once you getting up into the 6 range, and certainly past 8, you'll want to switch to 1-wire and use the DS18B20. Also, SPI and I2C are buses that are designed for on-device, short range communication; they are not buses that can accommodate placing sensors a significant distance away from the SBC itself.

Therefore, for designs where multiple sensors need to be spread out in an area but preferably connected to one SBC, the DS18B20 has many advantages:

  • the 1-wire bus is a long-distance bus that can let you connect sensors that are several metres away from your SBC
  • the DS18B20 has a wide temperature range, and high accuracy
  • the DS18B20 comes in several form-factors, one of which is in a temperature-appropriate and water-proof housing
  • you can connect 100s of them up reliably to a single RaspberryPi or other SBC
  • due to their unique serial numbers with a centrally-managed device prefix, Linux (and other OSes) are able to know what devices are connected to them (they're discoverable) and therefore do all the conversions internally for you, presenting user-space with a simple file to read containing each device's temperature (one file per device) automatically
Specific details of using a DS18B20 can be found in another one of my posts. Using multiple DS18B20s at a time is discussed in the post at this link.

30 Dec 2020

Multiple DS18B20 Temperature Probes


In my last post I hooked up one DS18B20 to a RaspberryPi. The neat thing about the DS18B20 and the 1-wire protocol is that multiple such devices can be connected together in a star topology. What's really great about this is that identifying an individual sensor doesn't depend on its position in a chain (for example) each device has its own unique 64-bit identifier. This means the layout of the probes doesn't have to be determined ahead of time. Also the length of the wires attached to the sensor can vary by a considerable amount. Therefore sensors near and far can be connected to the same microcontroller.

I had a number of varieties of protoboard, one of which is this type which features long buses:


This style of board works perfectly for this scenario.

I also happened to have a bunch of these x3 male headers. Most likely from some servo project.


Wouldn't it be great if there were a way to add a connector to the end of the temperature probes so they could plug into this header easily? As it turns out, it's Pololu to the rescue! Among the many things they sell, they also have crimp connector housings in various configurations, and all the other accessories to go with it.


I know this probably sounds like I have some relationship with Pololu but I don't. I know other electronics suppliers provide such items too, but Pololu's site makes it quite easy to buy the right things the first time around and give me the confidence to try this out (thanks to their supporting videos and information). After a little practice on test wires I'm able to add connectors to my temperature probes:


Cutting off a piece of protoboard and soldering on the header gives me a hub into which to plug all the temperature probes. Since we need a 4.7k pull-up resistor in the design anyway, I might as well add it to the hub so it's ready to go:


You'll notice there's no picture of the underside ๐Ÿ˜‰ It's bad enough showing this hack job from the top, I'm not about to show the disaster on the other side. Thankfully all the buses are still separate from each other, and that's all that matters ๐Ÿ˜‚

With the pull-up resistor in place I'm forcing the middle bus to be the ground. The connectors aren't keyed, so I just have to line up the VDD and DQ lines together myself.


…and with the RaspberryPi:


Now when I boot my device I get a kernel log message about my GPIO setup and one log message each for each of the sensors attached to my hub:

[    5.135283] gpio-25 (onewire@19): enforced open drain please flag it properly in DT/ACPI DSDT/board file
[    5.202823] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131bb70fee crc 30
[    5.497062] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b7ad963 crc f6
[    5.599175] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b62790b crc 83

Note: these messages don't appear side-by-side in the log, but they do appear in this order.

Now when I look in the 1-wire sysfs location I find:

root@raspberrypi3-64:~# cd /sys/bus/w1/devices/
root@raspberrypi3-64:/sys/bus/w1/devices# ls -l
lrwxrwxrwx    1 root     root             0 Dec 29 04:22 28-01131b62790b -> ../../../devices/w1_bus_master1/28-01131b62790b
lrwxrwxrwx    1 root     root             0 Dec 29 04:22 28-01131b7ad963 -> ../../../devices/w1_bus_master1/28-01131b7ad963
lrwxrwxrwx    1 root     root             0 Dec 29 04:22 28-01131bb70fee -> ../../../devices/w1_bus_master1/28-01131bb70fee
lrwxrwxrwx    1 root     root             0 Dec 29 04:22 w1_bus_master1 -> ../../../devices/w1_bus_master1

To read the temperatures of the probes I could visit each probe individually and simply "cat" the "temperature" file. This will cause the kernel to perform the "Convert T [44h]" command followed by the "Read Scratchpad [BEh]" command on each probe individually.

A small performance improvement can be had by visiting the master driver device and issuing a "trigger" command to its "therm_bulk_read" sysfs entry, then reading the temperatures from the probe devices individually. This causes the "Convert T [44h]" command to be issued to all the temperature probes connected to this master.

Notice that once the bulk command is given, the value of "therm_bulk_read" will read -1 if at least one sensor is still performing the conversion, 1 if one of the sensors has not had its temperature read out, and 0 once all the temperatures have been read for the most recent bulk conversion:

root@raspberrypi3-64:~# cd /sys/bus/w1/devices/
root@raspberrypi3-64:/sys/bus/w1/devices# ls -1
28-01131b62790b
28-01131b7ad963
28-01131bb70fee
w1_bus_master1
root@raspberrypi3-64:/sys/bus/w1/devices# cat w1_bus_master1/therm_bulk_read 
0
root@raspberrypi3-64:/sys/bus/w1/devices# echo "trigger" > w1_bus_master1/therm_bulk_read 
root@raspberrypi3-64:/sys/bus/w1/devices# cat w1_bus_master1/therm_bulk_read 
1
root@raspberrypi3-64:/sys/bus/w1/devices# cat 28-01131b62790b/temperature 
23375
root@raspberrypi3-64:/sys/bus/w1/devices# cat w1_bus_master1/therm_bulk_read 
1
root@raspberrypi3-64:/sys/bus/w1/devices# cat 28-01131b7ad963/temperature 28-01131bb70fee/temperature 
23125
23437
root@raspberrypi3-64:/sys/bus/w1/devices# cat w1_bus_master1/therm_bulk_read 
0

Note that I can't issue the bulk command and read out the status fast enough to demonstrate the -1 case. Writing the "trigger" to start the bulk command appears to block until all the probes have performed their temperature conversions.

The interesting thing about the bulk command is that it allows all the probes to check their temperatures at roughly the same time, then the code can take its time reading out the temperatures that existed when the bulk command was given. If each probe were to be visited one at a time, the timing of the temperature checks from all the probes would be skewed. This might not be a problem, but it's handy having this feature available.

Another neat thing about this setup is that the kernel actively probes the 1-wire bus during its operation. Therefore adding probes is plug-and-play at runtime! If a new probe is added to the bus at runtime, the kernel detects it, adds it to the list of devices, and prints a message indicating the probe's unique serial number. This feature makes it easier to add probes to an installation and correlate which probe is measuring which temperature. For example, if you have a project that needs 5 probes, each probe measuring a different part of a project, you can boot your hardware with the probes un-attached then attach them one-by-one to the bus at runtime taking note of their serial numbers and the part of the project each probe is measuring as they're being added.

29 Dec 2020

Temperature Readings with the DS18B20 and OpenEmbedded/Yocto



There are many ways to read a temperature in an electronics project. Probably the easiest way under Linux is with one of those pre-wired waterproof DS18B20 devices. Wire-up the probe to your RaspberryPi, enable a device-tree overlay, and read a file.

Wiring

The datasheet for the DS18B20 has all the information you'll need (and more). The probe has 3 wires: ground (black), DQ data in/out (yellow), and VDD (red). Technically the device doesn't actually need VDD connected, it can siphon enough parasitic power from DQ in normal operation. But since there's already a RaspberryPi in the design, it provides a convenient 5V, and connecting VDD makes the conversion potentially faster and more stable... might as well use it.

The datasheet recommends using a 4.7k pull-up on the DQ line. Grabbing 5V and ground from the RaspberryPi, I've wired up the probe as follows:


The 3-wire bundle comes from the probe, the individual wires run back to the RaspberryPi:


Connected to the RaspberryPi, the 3-wire bundle is my console cable, the individual wires run to the protoboard. The black wire is on ground, the red wire is on +5V. In my case I've decided to use the RaspberryPi's GPIO04, therefore the yellow wire is connected to pin07.



Build

By default the meta-raspberrypi OE/Yocto BSP layer uses the out-of-tree raspberrypi kernel. One of the differences between it and upstream is that the out-of-tree raspberrypi kernel contains all the device-tree overlays specific to the RaspberryPi. To interface with the DS18B20 the 1-wire overlay needs to be enabled in the RaspberryPi's config.txt. In OpenEmbedded/Yocto we use the RPI_EXTRA_CONFIG variable to enable arbitrary configurations in config.txt.

In addition to enabling the 1-wire protocol, we also need to specify the GPIO pin on which we want it to operate. In my specific case, given how I've wired the circuit, I'm using GPIO04, therefore I relay that information as follows:

RPI_EXTRA_CONFIG = "\
# enable 1-wire on gpio 4 \n\
dtoverlay=w1-gpio,gpiopin=4"

If you're building a core-image-minimal, you'll probably also want to add the following to your build:

CORE_IMAGE_EXTRA_INSTALL += " \
        ${MACHINE_EXTRA_RRECOMMENDS} \
        "

Building, flashing, and running the image from OpenEmbedded/Yocto you should see something along the following flash by on the serial console as it boots:

[    5.047539] gpio-4 (onewire@4): enforced open drain please flag it properly in DT/ACPI DSDT/board file
[    5.090044] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b62790b crc 83

This is good, it means everything is configured properly and the kernel has noticed the temperature probe connected to GPIO04 via 1-wire.

Note that in the case of the DS18B20, each device has a unique 64-bit serial number. So your output should be similar but will be slightly different. The "28" identifies this specific 1-wire device (i.e. the DS18B20), the hex value following the decimal point is the 48-bit unique serial number of my specific device. The last byte is a CRC of the first 56 bits.

Read A File

If everything is working properly and you've seen the previous messages in your system log as the device boots then everything should be set. Any devices that are detected can be found under /sys/bus/w1:

root@raspberrypi3-64:~# cd /sys/bus/w1
root@raspberrypi3-64:/sys/bus/w1# ls
devices            drivers            drivers_autoprobe  drivers_probe      uevent
root@raspberrypi3-64:/sys/bus/w1# cd devices/
root@raspberrypi3-64:/sys/bus/w1/devices# ls
28-01131b62790b  w1_bus_master1
root@raspberrypi3-64:/sys/bus/w1/devices# cd 28-01131b62790b/
root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b# ls -l
-rw-r--r--    1 root     root          4096 Dec 29 05:35 alarms
lrwxrwxrwx    1 root     root             0 Dec 29 05:35 driver -> ../../../bus/w1/drivers/w1_slave_drive
r
--w-------    1 root     root          4096 Dec 29 05:35 eeprom
-r--r--r--    1 root     root          4096 Dec 29 05:35 ext_power
drwxr-xr-x    3 root     root             0 Dec 29 04:26 hwmon
-r--r--r--    1 root     root          4096 Dec 29 05:35 id
-r--r--r--    1 root     root          4096 Dec 29 05:35 name
drwxr-xr-x    2 root     root             0 Dec 29 05:35 power
-rw-r--r--    1 root     root          4096 Dec 29 05:35 resolution
lrwxrwxrwx    1 root     root             0 Dec 29 05:35 subsystem -> ../../../bus/w1
-r--r--r--    1 root     root          4096 Dec 29 04:28 temperature
-rw-r--r--    1 root     root          4096 Dec 29 04:26 uevent
-rw-r--r--    1 root     root          4096 Dec 29 05:35 w1_slave
root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b# cat temperature 
23625
root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b# hexdump -C id
00000000  28 0b 79 62 1b 13 01 83                           |(.yb....|
00000008

As you can see, the temperature probe is automatically detected, and Linux handles all the details. Simply reading the "temperature" sysfs entry causes the kernel to ask the device to perform a temperature reading, then fetch the value from the device. Under the hood a lot of details are being handled by the kernel. Note, the reported temperature at this point is 23.625°C.

Notes

If I wanted to switch to, say, GPIO25 instead of GPIO04, all that would be required is to change where the yellow wire connects to the RaspberryPi's 40-pin header (switch from pin07 to pin22) and modify RPI_EXTRA_CONFIG as follows:

RPI_EXTRA_CONFIG = "\
# enable onewire on gpio 25 \n\
dtoverlay=w1-gpio,gpiopin=25"

Build, update the ยตSD card, apply power… Now when I boot I get:

[    5.113801] gpio-25 (onewire@19): enforced open drain please flag it properly in DT/ACPI DSDT/board file
[    5.473042] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b62790b crc 83

And everything continues to work as before:

root@raspberrypi3-64:~# cat /sys/bus/w1/devices/28-01131b62790b/temperature 
23500