arendst / Tasmota

Alternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at
https://tasmota.github.io/docs
GNU General Public License v3.0
22.18k stars 4.8k forks source link

DS18x20 parasitic power #20792

Closed wrlaw closed 8 months ago

wrlaw commented 8 months ago

PROBLEM DESCRIPTION

DS18x20 does not work out of the box using parasitic power. Looking at the source, a critical line of code seems to have been commented out.

REQUESTED INFORMATION

Make sure your have performed every step and checked the applicable boxes before submitting your issue. Thank you!

- [x] If using rules, provide the output of this command: `Backlog Rule1; Rule2; Rule3`:
```lua
  Rules output here:
No rules used
- [ ] Set `weblog` to 4 and then, when you experience your issue, provide the output of the Console log:
```lua
  Console output here:

TO REPRODUCE

Connect DS18x20 in a parasitic power configuration

EXPECTED BEHAVIOUR

The sensor should show the temperature but instead displays 85 degrees C. That is, I expected the precompiled binary to support DS18x20 sensors using parasitic power

SCREENSHOTS

void Ds18x20Convert(void) { for (uint32_t i = 0; i < DS18X20Data.gpios; i++) { ds = ds18x20_gpios[i]; ds->reset();

ifdef W1_PARASITE_POWER

// With parasite power held wire high at the end for parasitically powered devices
ds->write(W1_SKIP_ROM, 1);        // Address all Sensors on Bus
ds->write(W1_CONVERT_TEMP, 1);    // start conversion, no parasite power on at the end

else

ds->write(W1_SKIP_ROM);        // Address all Sensors on Bus
ds->write(W1_CONVERT_TEMP);    // start conversion, no parasite power on at the end

endif

// delay(750); // 750ms should be enough for 12bit conv } }

ADDITIONAL CONTEXT

Looking at the source, within the xsns_05_esp32_ds18x20.ino file I can see a key contributor to this problem. That is, there is a line of code with delay(750) in it but this line has been commented out. For a parasitically powered DS18x20 to be able to do a temperature conversion, it needs it's internal capacitor to be charged and the 750 ms delay provides time for this to occur. Without that delay, the conversion fails.

Another related issue that is also immediately noticeable is the need to define W1_PARASITE_POWER. With some additional code, this definition is not needed. That is, it is possible to determine whether a DS18x20 is parasitically powered by asking it. To determine if the sensor is parasitically powered, you can reset the 1 wire bus, select the specific device address, send the hex value 0xB4 to it and read back what it says. The code then becomes much simpler because there is no need to define W1_PARASITE_POWER. You can treat each device based on it's specific powering mode, parasitic or non-parasitic.

(Please, remember to close the issue when the problem has been addressed)

Jason2866 commented 8 months ago

You are welcome to provide a PR with the solution you have in mind.

arendst commented 8 months ago

As you're browsing the code have a better look regarding the not used delay. The function using it is called every odd second. The follow up code is then executed every even second so there is a delay of 1 second.

I suggest you dive deeper and find the real cause of your failing parasite powered device.

wrlaw commented 8 months ago

Thanks. I recompiled with W1_PARASITE_POWER defined and it now works. It would be easier for most people if they didn't have to go through the hassle of recompiling to get this to work.

As I said in my second paragraph above, there is no need to define the use of parasitic power statically, just ask the DS18x20 and it will tell you whether it's parasitically powered or not. Get rid of the W1_PARASITE_POWER definition and you get rid of these sort of issues. It should then work straight out of the box irrespective of whether the DS18x20 is parasitically powered or not. Also gives you the flexibility of using both parasitic powered DS18x20s and directly powered DS18x20s on the same device.

I don't claim to be a code maestro by any measure but below is some code I have used in another project in the past and it seemed to work. Borrow from it whatever you will.

bool using_parasitic_power (OneWire sensor, byte address) { // returns true if the device is using parasitic power bool parasitic = false; sensor->reset(); sensor->select(address); sensor->write(READPOWERSUPPLY); parasitic = !sensor->read_bit(); sensor->reset(); return parasitic; }

Note that READPOWERSUPPLY was previously defined as 0xB4 to avoid having magic numbers distributed randomly in the code. The pointer to the variable sensor passed as input to the routine is to an instance of a 1wire sensor created using the Arduino 1wire library and address is the unique address of the DS18x20 on the 1wire bus which can be determined prior to calling this routine. You could use something like this in your DS18x20 code instead of your current W1_PARASITE_POWER definition. Alternatively, rather than retesting for parasitic power every time you need to, you could determine it once and save the result as a boolean variable that you test each time instead. That will save you having to hit the 1wire bus each time you want to know.