深夜提醒

现在是深夜,建议您注意休息,不要熬夜哦~

🏮 🏮 🏮

新年快乐

祝君万事如意心想事成!

share-image
中
ESC

Connecting a DS18B20 Temperature Sensor to the ESP32

English 阅读中文版

After getting the ESP32 connected to WiFi and Bluetooth in the previous post, next I want to hook up some sensors to play with. Let’s start with the most common temperature sensor, the DS18B20. Its advantages are digital output, multiple devices on a single bus, and decent accuracy.

1. What You Need

  • One ESP32 development board
  • A DS18B20 temperature sensor module (or the bare sensor)
  • One 4.7kΩ resistor (for pull-up)
  • Some jumper wires

2. Wiring

The DS18B20 comes in a three-pin package. Wire it up as follows:

DS18B20 ESP32
VCC 3.3V
GND GND
DATA GPIO13

Note: a 4.7kΩ pull-up resistor must be connected between DATA and 3.3V; otherwise the OneWire bus is unstable and devices often can’t be read.

        4.7kΩ
3.3V ───\/\/\/───┬──── DATA (GPIO13)
│
DS18B20 ─┴────
VCC ──────────────── 3.3V
GND ──────────────── GND

Photo of the actual wiring:

温度计读数

3. Code to Read the Temperature

MicroPython ships with the onewire and ds18x20 modules — no extra installation needed.

from machine import Pin
import onewire
import ds18x20
import time

ds_pin = Pin(13)
ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin))


def read_temperature():
roms = ds_sensor.scan()
if not roms:
print('未检测到 DS18B20 设备,请检查接线')
return None

ds_sensor.convert_temp()
time.sleep_ms(750) # 等待转换完成

temps = []
for rom in roms:
temp = ds_sensor.read_temp(rom)
if isinstance(temp, float):
temps.append(round(temp, 2))
return temps


while True:
temps = read_temperature()
if temps:
print('当前温度:', temps, '°C')
time.sleep(1)

Code notes:

  • scan() scans the OneWire bus for devices and returns each device’s 64-bit ROM address.
  • convert_temp() sends the temperature-conversion command to all devices.
  • The DS18B20’s default 12-bit precision conversion takes about 750ms, so sleep_ms(750) is a must.
  • read_temp(rom) reads the temperature of the specified device.

4. Identifying the Sensor Model

Running the command below reads the ROM address and family code:

from machine import Pin
import onewire, ds18x20, binascii

ow = onewire.OneWire(Pin(13))
ds = ds18x20.DS18X20(ow)
roms = ds.scan()
for rom in roms:
print('ROM:', binascii.hexlify(rom), 'Family:', hex(rom[0]))

Output from the one I have on hand:

ROM: b'2824bb020002249f'  Family: 0x28

Family code 0x28 means it’s a DS18B20. If it were 0x10, it would be the older DS18S20.

5. Actual Readings

Serial output:

当前温度: [32.19] °C
当前温度: [32.19] °C
当前温度: [32.12] °C

The thermometer reading as photographed:

接线实物图

This temperature is room temperature plus the residual warmth from my fingers pinching the sensor, so it reads a bit higher than normal room temperature.

6. Common Issues

  • Device not detected: first check whether the pull-up resistor is connected and whether the jumper wires are firmly plugged in.
  • Temperature occasionally jumps to 85°C: this is the DS18B20’s power-on reset default; it usually means the conversion hadn’t finished when you read it. Lengthen the sleep_ms time to 1000ms.
  • Multiple sensors: scan() returns multiple ROMs; convert_temp() triggers all devices at once, then just read_temp(rom) one by one.

7. Uploading to the Blog Database in Real Time

blog-api already provides a temperature write endpoint, so no backend code is needed. The API details:

  • Write: POST https://your-api-domain.com/api/v1/temperature/realtime
  • Auth: header Authorization: Bearer sk_xxx
  • Request body:
{
"value": 26.56,
"timestamp": 1723968000000,
"device_id": "2824bb020002249f",
"source": "esp32-ds18b20"
}

7.1 Creating an API Token

Log into the blog-api admin console and create an API Token with write permission, or just use curl:

curl -X POST https://your-api-domain.com/api/v1/admin/api-tokens \
-H "Authorization: Bearer <你的JWT>" \
-H "Content-Type: application/json" \
-d '{"name":"ESP32温度上传","permissions":"write"}'

Put the returned sk_xxx into api_config.py:

API_BASE_URL = 'https://your-api-domain.com'
API_TOKEN = 'sk_你的Token'
UPLOAD_INTERVAL_MS = 300000 # 5 分钟

7.2 The Upload Script

Core logic of temp_uploader.py:

import network
import time
import urequests
import ujson
import ntptime
from machine import Pin
import onewire
import ds18x20
from wifi_config import SSID, PASSWORD
from api_config import API_BASE_URL, API_TOKEN, UPLOAD_INTERVAL_MS

DS_PIN = 13


def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected():
pass
print('IP:', wlan.ifconfig()[0])


def sync_ntp():
try:
ntptime.settime()
print('NTP synced')
except Exception as e:
print('NTP sync failed:', e)


def read_temperature():
ds_sensor = ds18x20.DS18X20(onewire.OneWire(Pin(DS_PIN)))
roms = ds_sensor.scan()
if not roms:
return None, None
ds_sensor.convert_temp()
time.sleep_ms(750)
rom = roms[0]
temp = ds_sensor.read_temp(rom)
rom_hex = ''.join('{:02x}'.format(b) for b in rom)
return round(temp, 2), rom_hex


def upload_temperature(value, device_id):
url = API_BASE_URL + '/api/v1/temperature/realtime'
headers = {
'Authorization': 'Bearer ' + API_TOKEN,
'Content-Type': 'application/json',
}
# 当前 MicroPython 的 time.time() 使用 2000-01-01 为 epoch,
# 需要加上 1970-01-01 到 2000-01-01 的秒数偏移,转换为标准 Unix 毫秒时间戳
unix_timestamp_ms = (time.time() + 946684800) * 1000
payload = {
'value': value,
'timestamp': unix_timestamp_ms,
'device_id': device_id,
'source': 'esp32-ds18b20',
}
response = urequests.post(url, headers=headers, data=ujson.dumps(payload), timeout=15)
status = response.status_code
response.close()
return 200 <= status < 300


def main():
connect_wifi()
sync_ntp()
while True:
temp, rom = read_temperature()
if temp is not None:
print('Temperature:', temp, '°C')
upload_temperature(temp, rom)
time.sleep_ms(UPLOAD_INTERVAL_MS)


main()

Once running, the ESP32 reads the temperature every 5 minutes and uploads it to blog-api’s realtime_temperature_records table.

7.3 Verifying the Data

Public query endpoints:

# 最新一条
curl "https://your-api-domain.com/api/v1/public/temperature/realtime?user_id=1"

# 最近 7 天历史
curl "https://your-api-domain.com/api/v1/public/temperature/history?user_id=1&days=7"

Just replace user_id with your actual user ID.

8. Showing It Off

After the data was flowing, I added a “Current Hangzhou Temperature” widget to my blog homepage; clicking the temperature pops up trend charts for the last 1 day and last 30 days. The image below is the live effect, screenshotted just this morning:

博客首页温度趋势

9. Video Demo

Here’s a video demo of this tinkering session:

10. Next Steps

I could add a temperature card to the blog frontend that calls /api/v1/public/temperature/realtime to show the current ambient temperature, plus a line chart calling /history for the 24-hour trend — and that would make a complete wireless thermometer dashboard.

文章作者:阿文
文章链接: https://www.awen.me/post/51fea752.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿文的博客!

评论

0 条评论
😀😃😄 😁😅😂 🤣😊😇 🙂🙃😉 😌😍🥰 😘😗😙 😚😋😛 😝😜🤪 🤨🧐🤓 😎🥸🤩 🥳😏😒 😞😔😟 😕🙁☹️ 😣😖😫 😩🥺😢 😭😤😠 😡🤬🤯 😳🥵🥶 😱😨😰 😥😓🤗 🤔🤭🤫 🤥😶😐 😑😬🙄 😯😦😧 😮😲🥱 😴🤤😪 😵🤐🥴 🤢🤮🤧 😷🤒🤕 🤑🤠😈 👿👹👺 🤡💩👻 💀☠️👽 👾🤖🎃 😺😸😹 😻😼😽 🙀😿😾 👍👎👏 🙌👐🤲 🤝🤜🤛 ✌️🤞🤟 🤘👌🤏 👈👉👆 👇☝️✋ 🤚🖐️🖖 👋🤙💪 🦾🖕✍️ 🙏💅🤳 💯💢💥 💫💦💨 🕳️💣💬 👁️‍🗨️🗨️🗯️ 💭💤❤️ 🧡💛💚 💙💜🖤 🤍🤎💔 ❣️💕💞 💓💗💖 💘💝💟 ☮️✝️☪️ 🕉️☸️✡️ 🔯🕎☯️ ☦️🛐⛎ ♈♉♊ ♋♌♍ ♎♏♐ ♑♒♓ 🆔⚛️🉑 ☢️☣️📴 📳🈶🈚 🈸🈺🈷️ ✴️🆚💮 🉐㊙️㊗️ 🈴🈵🈹 🈲🅰️🅱️ 🆎🆑🅾️ 🆘❌⭕ 🛑⛔📛 🚫💯💢 ♨️🚷🚯 🚳🚱🔞 📵🚭❗ ❕❓❔ ‼️⁉️🔅 🔆〽️⚠️ 🚸🔱⚜️ 🔰♻️✅ 🈯💹❇️ ✳️❎🌐 💠Ⓜ️🌀 💤🏧🚾 ♿🅿️🈳 🈂🛂🛃 🛄🛅🛗 🚀🛸🚁 🚉🚆🚅 ✈️🛫🛬 🛩️💺🛰️
加载中...

留言反馈

😀😃😄 😁😅😂 🤣😊😇 🙂🙃😉 😌😍🥰 😘😗😙 😚😋😛 😝😜🤪 🤨🧐🤓 😎🥸🤩 🥳😏😒 😞😔😟 😕🙁☹️ 😣😖😫 😩🥺😢 😭😤😠 😡🤬🤯 😳🥵🥶 😱😨😰 😥😓🤗 🤔🤭🤫 🤥😶😐 😑😬🙄 😯😦😧 😮😲🥱 😴🤤😪 😵🤐🥴 🤢🤮🤧 😷🤒🤕 🤑🤠😈 👿👹👺 🤡💩👻 💀☠️👽 👾🤖🎃 😺😸😹 😻😼😽 🙀😿😾 👍👎👏 🙌👐🤲 🤝🤜🤛 ✌️🤞🤟 🤘👌🤏 👈👉👆 👇☝️✋ 🤚🖐️🖖 👋🤙💪 🦾🖕✍️ 🙏💅🤳 💯💢💥 💫💦💨 🕳️💣💬 👁️‍🗨️🗨️🗯️ 💭💤❤️ 🧡💛💚 💙💜🖤 🤍🤎💔 ❣️💕💞 💓💗💖 💘💝💟 ☮️✝️☪️ 🕉️☸️✡️ 🔯🕎☯️ ☦️🛐⛎ ♈♉♊ ♋♌♍ ♎♏♐ ♑♒♓ 🆔⚛️🉑 ☢️☣️📴 📳🈶🈚 🈸🈺🈷️ ✴️🆚💮 🉐㊙️㊗️ 🈴🈵🈹 🈲🅰️🅱️ 🆎🆑🅾️ 🆘❌⭕ 🛑⛔📛 🚫💯💢 ♨️🚷🚯 🚳🚱🔞 📵🚭❗ ❕❓❔ ‼️⁉️🔅 🔆〽️⚠️ 🚸🔱⚜️ 🔰♻️✅ 🈯💹❇️ ✳️❎🌐 💠Ⓜ️🌀 💤🏧🚾 ♿🅿️🈳 🈂🛂🛃 🛄🛅🛗 🚀🛸🚁 🚉🚆🚅 ✈️🛫🛬 🛩️💺🛰️