ESPHome  2024.11.0
dallas_temp.cpp
Go to the documentation of this file.
1 #include "dallas_temp.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace dallas_temp {
6 
7 static const char *const TAG = "dallas.temp.sensor";
8 
9 static const uint8_t DALLAS_MODEL_DS18S20 = 0x10;
10 static const uint8_t DALLAS_COMMAND_START_CONVERSION = 0x44;
11 static const uint8_t DALLAS_COMMAND_READ_SCRATCH_PAD = 0xBE;
12 static const uint8_t DALLAS_COMMAND_WRITE_SCRATCH_PAD = 0x4E;
13 static const uint8_t DALLAS_COMMAND_COPY_SCRATCH_PAD = 0x48;
14 
16  switch (this->resolution_) {
17  case 9:
18  return 94;
19  case 10:
20  return 188;
21  case 11:
22  return 375;
23  default:
24  return 750;
25  }
26 }
27 
29  ESP_LOGCONFIG(TAG, "Dallas Temperature Sensor:");
30  if (this->address_ == 0) {
31  ESP_LOGW(TAG, " Unable to select an address");
32  return;
33  }
34  LOG_ONE_WIRE_DEVICE(this);
35  ESP_LOGCONFIG(TAG, " Resolution: %u bits", this->resolution_);
36  LOG_UPDATE_INTERVAL(this);
37 }
38 
40  if (this->address_ == 0)
41  return;
42 
43  this->status_clear_warning();
44 
45  this->send_command_(DALLAS_COMMAND_START_CONVERSION);
46 
47  this->set_timeout(this->get_address_name(), this->millis_to_wait_for_conversion_(), [this] {
48  if (!this->read_scratch_pad_() || !this->check_scratch_pad_()) {
49  this->publish_state(NAN);
50  return;
51  }
52 
53  float tempc = this->get_temp_c_();
54  ESP_LOGD(TAG, "'%s': Got Temperature=%.1f°C", this->get_name().c_str(), tempc);
55  this->publish_state(tempc);
56  });
57 }
58 
60  for (uint8_t &i : this->scratch_pad_) {
61  i = this->bus_->read8();
62  }
63 }
64 
66  bool success;
67  {
68  InterruptLock lock;
69  success = this->send_command_(DALLAS_COMMAND_READ_SCRATCH_PAD);
70  if (success)
71  this->read_scratch_pad_int_();
72  }
73  if (!success) {
74  ESP_LOGW(TAG, "'%s' - reading scratch pad failed bus reset", this->get_name().c_str());
75  this->status_set_warning("bus reset failed");
76  }
77  return success;
78 }
79 
81  ESP_LOGCONFIG(TAG, "setting up Dallas temperature sensor...");
82  if (!this->check_address_())
83  return;
84  if (!this->read_scratch_pad_())
85  return;
86  if (!this->check_scratch_pad_())
87  return;
88 
89  if ((this->address_ & 0xff) == DALLAS_MODEL_DS18S20) {
90  // DS18S20 doesn't support resolution.
91  ESP_LOGW(TAG, "DS18S20 doesn't support setting resolution.");
92  return;
93  }
94 
95  uint8_t res;
96  switch (this->resolution_) {
97  case 12:
98  res = 0x7F;
99  break;
100  case 11:
101  res = 0x5F;
102  break;
103  case 10:
104  res = 0x3F;
105  break;
106  case 9:
107  default:
108  res = 0x1F;
109  break;
110  }
111 
112  if (this->scratch_pad_[4] == res)
113  return;
114  this->scratch_pad_[4] = res;
115 
116  {
117  InterruptLock lock;
118  if (this->send_command_(DALLAS_COMMAND_WRITE_SCRATCH_PAD)) {
119  this->bus_->write8(this->scratch_pad_[2]); // high alarm temp
120  this->bus_->write8(this->scratch_pad_[3]); // low alarm temp
121  this->bus_->write8(this->scratch_pad_[4]); // resolution
122  }
123 
124  // write value to EEPROM
125  this->send_command_(DALLAS_COMMAND_COPY_SCRATCH_PAD);
126  }
127 }
128 
130  bool chksum_validity = (crc8(this->scratch_pad_, 8) == this->scratch_pad_[8]);
131 
132 #ifdef ESPHOME_LOG_LEVEL_VERY_VERBOSE
133  ESP_LOGVV(TAG, "Scratch pad: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X (%02X)", this->scratch_pad_[0],
134  this->scratch_pad_[1], this->scratch_pad_[2], this->scratch_pad_[3], this->scratch_pad_[4],
135  this->scratch_pad_[5], this->scratch_pad_[6], this->scratch_pad_[7], this->scratch_pad_[8],
136  crc8(this->scratch_pad_, 8));
137 #endif
138  if (!chksum_validity) {
139  ESP_LOGW(TAG, "'%s' - Scratch pad checksum invalid!", this->get_name().c_str());
140  this->status_set_warning("scratch pad checksum invalid");
141  }
142  return chksum_validity;
143 }
144 
146  int16_t temp = (this->scratch_pad_[1] << 8) | this->scratch_pad_[0];
147  if ((this->address_ & 0xff) == DALLAS_MODEL_DS18S20) {
148  return (temp >> 1) + (this->scratch_pad_[7] - this->scratch_pad_[6]) / float(this->scratch_pad_[7]) - 0.25;
149  }
150  switch (this->resolution_) {
151  case 9:
152  temp &= 0xfff8;
153  break;
154  case 10:
155  temp &= 0xfffc;
156  break;
157  case 11:
158  temp &= 0xfffe;
159  break;
160  case 12:
161  default:
162  break;
163  }
164 
165  return temp / 16.0f;
166 }
167 
168 } // namespace dallas_temp
169 } // namespace esphome
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition: component.cpp:69
uint8_t crc8(const uint8_t *data, uint8_t len)
Calculate a CRC-8 checksum of data with size len.
Definition: helpers.cpp:95
void status_clear_warning()
Definition: component.cpp:166
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
virtual void write8(uint8_t val)=0
Write a word to the bus. LSB first.
Helper class to disable interrupts.
Definition: helpers.h:597
bool check_address_()
find an address if necessary should be called from setup
Definition: one_wire.cpp:23
const std::string & get_address_name()
Helper to create (and cache) the name for this sensor. For example "0xfe0000031f1eaf29".
Definition: one_wire.cpp:8
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
OneWireBus * bus_
pointer to OneWireBus instance
Definition: one_wire.h:31
virtual uint8_t read8()=0
Read an 8 bit word from the bus.
bool send_command_(uint8_t cmd)
send command on the bus
Definition: one_wire.cpp:16
const StringRef & get_name() const
Definition: entity_base.cpp:10
uint16_t millis_to_wait_for_conversion_() const
Get the number of milliseconds we have to wait for the conversion phase.
Definition: dallas_temp.cpp:15