Multiple DS18B20 with Photon

OK, indeed, I start to see why this went wrong. Thanks!

I just wanted to strip those commands which I thought were taking care of the two buses, but I was wrong!

I suppose I better use your unmodified library together with my sketch, even if I use only one bus with 6 sensors, right?

I checked if that combination compiles with Particle DEV and it does.

Question: Is there a way to make the Particle.variables to work?

It won’t with ‘float’ variables and if I modify all to ‘double’ the compiler does not agree…

Sure, but you need to post what error you get when you change the variables to doubles. As far as changing the code to only work with one string of sensors (instead of the two busses), you should get rid of select and the things that go with it.

void getTemperatures(float temps[], int tempsCount, int pin, int select)
{
    OneWire ds = OneWire(pin);
    ds.reset();
    ds.skip();          // Make all devices start the temperature conversion
    ds.write(0x44, 0);  // Tell it to start a conversion (second argument: 1 = parasite power, 0 = powered mode)

    delay(1000);       //  Wait 1 sec for conversion
    ds.reset();

    for (int i=0; i<tempsCount; i++)
    {
        ds.write(0xBE,0);

        byte data0 = ds.read();
        byte data1 = ds.read();
        ds.reset();

        int16_t raw = (data1 << 8) | data0;
        celsius = (float)raw * 0.0625; // DS18B20 sensor = 12 bit resolution device

        temps[i] = celsius;
    }
}
1 Like

OK @Ric , that’s probably the only unnecessary part with one bus.
And it compiles with my sketch…

When I uncomment my 6 Particle.variables, I get the following errors:

Then I change the float:

float TopH, TopL, MidH, MidL, BotH, BotL;
float* temps1[] = {&TopH, &TopL, &MidH, &MidL, &BotH, &BotL};

To double:

double TopH, TopL, MidH, MidL, BotH, BotL;
double* temps1[] = {&TopH, &TopL, &MidH, &MidL, &BotH, &BotL};

=> Then I get the following error:

Right, the getTemperatures() function is still setup for floats, so change it to doubles:

void getTemperatures(double temps[], int tempsCount, int pin, int select)
{
    OneWire ds = OneWire(pin);
    ds.reset();
    ds.skip();          // Make all devices start the temperature conversion
    ds.write(0x44, 0);  // Tell it to start a conversion (second argument: 1 = parasite power, 0 = powered mode)

    delay(1000);       //  Wait 1 sec for conversion
    ds.reset();

    for (int i=0; i<tempsCount; i++)
    {
        ds.write(0xBE,0);

        byte data0 = ds.read();
        byte data1 = ds.read();
        ds.reset();

        int16_t raw = (data1 << 8) | data0;
        celsius = (double)raw * 0.0625; // DS18B20 sensor = 12 bit resolution device

        temps[i] = celsius;
    }
}

I did this also, but it still does not compile and I still get the same error message…
Or could this be some kind of ‘cache’ issue?

I suppose it will remain a mystery why we can’t publish those 6 variables as Particle.variables…

Therefore I am trying to go around this problem:

I am now using @Ric 's library (see above) and in my sketch below, I calculate the average value of the temperatures in the 5 zones (6 temperatures) and store them in ‘doubles’:

#include "Dallas.h" // This library is NOT the same as in the Particle IDE!

float TopH, TopL, MidH, MidL, BotH, BotL; // The names you want to call the sensors, created in the array(s) in Dallas.cpp
float* temps1[] = {&TopH, &TopL, &MidH, &MidL, &BotH, &BotL}; // Group1: 6 waterproof sensors
double Av1, Av2, Av3, Av4, Av5; // To store average temperatures

void setup()
{
  Serial.begin(9600);
  delay(3000);

  // Particle.variable does not work with 'float' variables. OK with 'double'... (But then I get weird errors...)
  Particle.variable("ECO_Av1", Av1);
  Particle.variable("ECO_Av2", Av2);
  Particle.variable("ECO_Av3", Av3);
  Particle.variable("ECO_Av4", Av4);
  Particle.variable("ECO_Av5", Av5);
}


void loop()
{
  // Read sensor values! Argument 1: N° of sensors, Argument 2: Particle I/O pin , Argument 3: Select array of addresses (addrs0, addrs1 ...) in Dallas.cpp
  getTemperatures(*temps1, 6, D3, 0); // From now you can use the chosen sensor names as if it were ordinary floating type variables...

  // Serial output:
  Serial.printf("TopH = %.1f TopL = %.1f MidH = %.1f MidL = %.1f BotH = %.1f BotL = %.1f", TopH, TopL, MidH, MidL, BotH, BotL); Serial.println();

  // Calculate the average temperature in each of the 5 zones:
  Av1 = (TopH + TopL)/2;
  Av2 = (TopL + MidH)/2;
  Av3 = (MidH + MidL)/2;
  Av4 = (MidL + BotH)/2;
  Av5 = (BotH + BotL)/2;
  // Next steps: Calculate the energy in each of the 5 zones and add them together: Total buffer energy content...

  delay(2000); // Minimum 1000 !!!
}

It compiles and when running, these 5 double variables are now published but it looks like something is wrong: I expect temperatures between 20 - 80°C and I see these results:

Any idea where this still goes wrong?

Before calling it a day, I have integrated @Ric 's full library (with 2 buses of sensors) into my revised sketch, so that I can also compile in the Web-IDE.

Here it is:

// Buffer-TEST.ino = Sketch to read hardcoded DS18B20 sensors by their HEX sensor code and call them from the loop() by their names...

// Choose one of 2 possibilities:
// 1) For use in the IDE:
//#include "OneWire/OneWire.h"
// 2) For use with Particle Dev:
#include "OneWire.h"

double celsius;

// Group sensors in their bus (on one I/O pin) ; [6][8] means: 6 sensor codes with 8 bytes.
// Attention: If the 2 types of sensors are mixed, you must group DS18S20 sensors in one bus and DS18B20 in another bus. You must adapt below code (if(select == 0 or 1)) to the sensor type...
byte addrs0[6][8] = {{0x28,0xFF,0x0D,0x4C,0x05,0x16,0x03,0xC7}, {0x28,0xFF,0x25,0x1A,0x01,0x16,0x04,0xCD}, {0x28,0xFF,0x89,0x19,0x01,0x16,0x04,0x57}, {0x28,0xFF,0x21,0x9F,0x61,0x15,0x03,0xF9}, {0x28,0xFF,0x16,0x6B,0x00,0x16,0x03,0x08}, {0x28,0xFF,0x90,0xA2,0x00,0x16,0x04,0x76}};
// Unused sensors: {0x28,0x3A,0xBC,0x07,0x00,0x00,0x80,0x58}, {0x28,0x72,0x03,0x04,0x00,0x00,0x80,0x24}, {0x28,0xD4,0xE7,0x03,0x00,0x00,0x80,0x89}, {0x28,0x78,0xF9,0x03,0x00,0x00,0x80,0x76}, {0x28,0x70,0xAD,0x07,0x00,0x00,0x80,0x53}, {0x28,0x40,0xE1,0x03,0x00,0x00,0x80,0x78}}; // 12x DS18B20 Waterproof wired sensors
byte addrs1[3][8] = {{0x10,0xE9,0x6B,0x0A,0x03,0x08,0x00,0xAC}, {0x10,0x44,0x4E,0x0B,0x03,0x08,0x00,0x1F}, {0x28, 0xD, 0xD3, 0xE2, 0x3, 0x0, 0x0, 0xEE}};// 2x DS18S20 TO92 sensors (Third code is from Ric, not on the bus: Test error handling!)

double Tmin = 25; // Minimum ECO boiler temperature

float TopH, TopL, MidH, MidL, BotH, BotL; // The names you want to call the sensors, created in the array(s) in Dallas.cpp
float* temps1[] = {&TopH, &TopL, &MidH, &MidL, &BotH, &BotL}; // Group1: 6 waterproof sensors

double Av1, Av2, Av3, Av4, Av5; // To store average temperatures
double Q1, Q2, Q3, Q4, Q5, Qtot; // To store energy


void setup()
{
  Serial.begin(9600);
  delay(3000);

  // Particle.variable does not work with 'float' variables. OK with 'double'... (But then I get weird errors...)
  Particle.variable("ECO_Av1", Av1);
  Particle.variable("ECO_Av2", Av2);
  Particle.variable("ECO_Av3", Av3);
  Particle.variable("ECO_Av4", Av4);
  Particle.variable("ECO_Av5", Av5);
  Particle.variable("ECO-Qtot", Qtot);
}


void loop()
{
  // Read sensor values! Argument 1: N° of sensors, Argument 2: Particle I/O pin , Argument 3: Select array of addresses (addrs0, addrs1 ...) in Dallas.cpp
  getTemperatures(*temps1, 6, D3, 0); // From now you can use the chosen sensor names as if it were ordinary floating type variables...

  // Serial output:
  Serial.printf("TopH = %.1f TopL = %.1f MidH = %.1f MidL = %.1f BotH = %.1f BotL = %.1f", TopH, TopL, MidH, MidL, BotH, BotL); Serial.println();

  // Calculate the average temperature in each of the 5 zones:
  Av1 = (TopH + TopL)/2;
  Av2 = (TopL + MidH)/2;
  Av3 = (MidH + MidL)/2;
  Av4 = (MidL + BotH)/2;
  Av5 = (BotH + BotL)/2;

  // Calculate the energy in each of the 5 zones:
  Q1 = (Av1-Tmin)*110*1.163/1000; // Energy in top zone (kWh)
  Q2 = (Av2-Tmin)*90*1.163/1000; // Energy in top/mid zone (kWh)
  Q3 = (Av3-Tmin)*90*1.163/1000; // Energy in middle zone (kWh)
  Q4 = (Av4-Tmin)*90*1.163/1000; // Energy in mid/bottom zone (kWh)
  Q5 = (Av5-Tmin)*110*1.163/1000; // Energy in bottom zone (kWh)
  Qtot = Q1+Q2+Q3+Q4+Q5; // Total energy content in Buffer

  delay(5000); // Minimum 1000 !!!
}


void getTemperatures(float temps[], int tempsCount, int pin, int select)
{
    OneWire ds = OneWire(pin);
    ds.reset();
    ds.skip();          // Make all devices start the temperature conversion
    ds.write(0x44, 0);  // Tell it to start a conversion (second argument: 1 = parasite power, 0 = powered mode)

    delay(1000);       //  Wait 1 sec for conversion
    ds.reset();

    for (int i=0; i<tempsCount; i++)
    {
        switch (select)
        {
            case 0:
                ds.select(addrs0[i]);
                break;
            case 1:
                ds.select(addrs1[i]);
                break;
        }

        ds.write(0xBE,0);

        byte data0 = ds.read();
        byte data1 = ds.read();
        ds.reset();

        // If you mix both types of sensors, you need this branching:
        if (select == 0)
        {
            int16_t raw = (data1 << 8) | data0;
            celsius = (float)raw * 0.0625; // DS18B20 sensor = 12 bit resolution device
        }
        else if (select == 1)
        {
            int16_t raw = data0;
            celsius = (float)raw * 0.5; // DS18S20 sensor = 9 bit resolution device
        }

        /*
        // If you use only DS18B20 sensors, you can keep it simpler:
        int16_t raw = (data1 << 8) | data0;
        celsius = (float)raw * 0.0625; // For DS18B20 sensors
        */

        temps[i] = celsius;
    }
}

The results I get from the Particle variables are still not what I expect:
(Temperatures between 20 - 80°C)

The last variable should be around 20…

I would be very glad to get some tips to find a way to reading the correct data…
Thanks on beforehand!
:older_man:

in Particle world floats are 32 bits wide. Doubles are 64 bits wide.

particle variables are String, int or doubles.

you are using pointers so the type is critical. if you send a 64bit pointer to a 32 bit data type’s location, you will get all four bytes plus four more!

So, if the Particle variable is expecting a 64 bit number, and is pointed to a 32 bit number, that may be what’s causing your problem.

You may want to consider making all of your float variables, function parameters and returns all double, as was pointed out.

1 Like

Hi @FiDel

In your code above, you subtract 25.0 from the averages to compute the Q values so 36.65625-25.0 = 11.65625 and 10.34375 - 25 = -14.65625, and all the other Av values are zero, so they contribute -25.0 scaled by the constants to sum. When I do that math in a spreadsheet, I get -8.474635625 so I think that part is working approximately as you want it to, given that Av3 through Av5 are zero.

Can you try just ignoring the getTemperatures for a minute and set the values to known things like 20.0, 25.0, 30.0, 35.0, 40.0 and see if the Particle variables are working as you expect?

For the record, I would not write code like float *temps1[] = {&TopH, &TopL ...}. Instead I would just use an array of floats or doubles directly. I have suspicions about the pointer to addresses of vars stuff and would just rewrite it to be more direct.

2 Likes

The whole rationale for this code (from way back when) was based on being able to use meaningful names for the individual variables (as opposed to temps[0], temps[1], etc.), but also to use them in an array for efficiency. Given what his code looks like now, I don't think that rationale still makes sense. Also, the getTemperatures() function was in a separate file, so using it as is, but moved into the .ino file, isn't really the best way now either.

2 Likes

To achieve that using enum to provide meaningful indexes instead of anonymous numbers would be another way to achieve the same thing with less potential for pointer trouble.

2 Likes

Wow, thanks for all those tips!
I am not a professional programmer, so I can imagine what it’s all about but could not write code on that level…

As @Ric pointed out, it all started out with the need to be able to use meaningful names for variables for the temperatures. In this example you can probably imagine why.

In this project, I need a lot of these DS18B20 sensors:
For this heating buffer alone I need 6 to calculate heat contents. And I have 2 more buffers where I want to use the same code. Apart from these, I will need about 20 more sensors for monitoring all devices. (Heat pumps, solar system, wood fires, pumps, solenoids…)

@BulldogLowell : Yes, I get your point of not mixing those variable types. But I tried to change @Ric 's original library and my script to doubles in order to be able to create particle.variables.
(PS: Reason for the ‘particle.variables’: I can’t check my Photons in this project all the time using ‘serial feedback’ as I’m living about 50 km from there…)

@bko : Your focus is the calculation of the heat contents at the bottom of the sketch: Indeed, I can see that the results I see through the Particle.variables are consistent with the temperatures obtained from @Ric 's library. The calculations will be verified later with good temperature values, but right now my focus is the lack of reliable variables with 6 temperatures… Using arrays is fine for me, but the final temperature variables must be floats or doubles but important: The names must make sense. (like TopH, TopL…)

@Ric : Indeed, the library you constructed in 2016 did the job for me in a nice way, thanks! It allows mixing of the various types of sensors by keeping them is separate “buses”.
But today, I want to simplify it as to use only one I/O pin for many DS18B20 sensors, so only one “bus” instead of 2 like in your original.
Also, I would prefer to combine the commands in the library into the sketch so that I can compile also from the Web IDE if necessary. (I still prefer Particle Dev!)

@ScruffR : Thanks for throwing in another promising approach!
But I can’t do this on my own… :wink:

Today I will go to the project to do some other work.
So I will be able to check this Photon’s output with revised sketches via serial connection…

:confused:

Using the little '+' button in the top right will allow you to add your own custom libraries to an app. That way you can keep things clean and separated :slight_smile:

1 Like

@Moors7 : OK, thanks for this tip, I never tried that!
In that case yes, it might be better to leave @Ric 's library untouched.

But yesterday I tried to use it as it is (Multiple DS18B20 with Photon) and there still was a problem with the output…

:particle:

I just arrived at the project and connected the serial monitor, to see if the output is different from the particle.variables:

Serial output:
TopH = 48.1 TopL = 20.3 MidH = 0.0 MidL = 0.0 BotH = 0.0 BotL = 0.0
TopH = 48.1 TopL = 20.3 MidH = 0.0 MidL = 0.0 BotH = 0.0 BotL = 0.0
TopH = 48.1 TopL = 20.3 MidH = 0.0 MidL = 0.0 BotH = 0.0 BotL = 0.0
TopH = 48.1 TopL = 20.3 MidH = 0.0 MidL = 0.0 BotH = 0.0 BotL = 0.0
TopH = 48.1 TopL = 20.3 MidH = 0.0 MidL = 0.0 BotH = 0.0 BotL = 0.0
TopH = 48.1 TopL = 20.3 MidH = 0.0 MidL = 0.0 BotH = 0.0 BotL = 0.0

This what I see at the same time in the Particle console:

This seems correct, as the console shows the averages of two sensors: (48.1+20.3)/2= 34.2°
But only the first temperature is correct.
The other temperatures should be between 20 - 30°.

Any idea what I can do to read also the other temperatures correctly?

(The Photon is still flashed with the latest version without library)

:older_man:

Hi @FiDel

At this point I would double and triple check the addresses you are using for sensors 3-6. If those are not right, then you would get the results you are getting. You can run separate code that scans the one wire bus and reports the addresses found.

One problem with your approach here has been that the information you are sending is derived and not the raw data, so sometimes it seemed to me like you were complaining that something was wrong in the code that computed these derived values or in the Particle.variable() code itself. I was trying to point out that does not appear to be the case at all and all the values make sense given that you are getting zeros for some of the sensor values.

1 Like

Thanks @bko ! Tonight I will definitely re-scan all sensors on that bus.
I had marked each of them with their code, but you never know...

I will try to make a sketch which can send the addresses via Particle.events, because the Photon is 50 km away...

I don't understand exactly what this means...
Do you mean that I send the calculated average temperatures instead of the temperatures v ia Particle.variables?

The reason of that is that the temperatures are floating variables which can't be published as Particle.variables. Calculating average values in double format solves this issue.
Anyway, I appreciater your previous comments also!

:older_man:

You really should try to fix that problem first, rather than trying to kluge something together. There's no reason you shouldn't be able to do everything in doubles. Maybe you can email me again, and send me your entire code, so I can look at what you have now.

2 Likes

@bko : I just uploaded another sketch to that Photon 50 km away and promptly got confirmation that all 6 sensors are OK, outputting expected temperatures and they have the same addresses as used in the current sketch…

Here is the current console output:

Sensor# 6 (28FF90A200160476) = : +19.7500
Sensor# 5 (28FF166B00160308) = : +21.0625
Sensor# 4 (28FF219F611503F9) = : +26.1250
Sensor# 3 (28FF891901160457) = : +38.1875
Sensor# 2 (28FF251A011604CD) = : +43.4375
Sensor# 1 (28FF0D4C051603C7) = : +45.9375

@Ric : Thanks for your generous offer: I will send you my current project folder(s), OK?

:older_man:

1 Like

In case some of you develop a similar project, this is the final sketch @ric has helped to create last weekend:

#include <OneWire.h>
const int oneWirePin = D3;
OneWire ds = OneWire(oneWirePin);

byte addrs0[6][8] = {{0x28,0xFF,0x0D,0x4C,0x05,0x16,0x03,0xC7}, {0x28,0xFF,0x25,0x1A,0x01,0x16,0x04,0xCD}, {0x28,0xFF,0x89,0x19,0x01,0x16,0x04,0x57}, {0x28,0xFF,0x21,0x9F,0x61,0x15,0x03,0xF9}, {0x28,0xFF,0x16,0x6B,0x00,0x16,0x03,0x08}, {0x28,0xFF,0x90,0xA2,0x00,0x16,0x04,0x76}};
byte addrs1[3][8] = {{0x10,0xE9,0x6B,0x0A,0x03,0x08,0x00,0xAC}, {0x10,0x44,0x4E,0x0B,0x03,0x08,0x00,0x1F}};

double TopH, TopL, MidH, MidL, BotH, BotL;
double* temps[] = {&TopH, &TopL, &MidH, &MidL, &BotH, &BotL};

double celsius;
double Tmin = 35;
double Av1, Av2, Av3, Av4, Av5;
double Q1, Q2, Q3, Q4, Q5, Qtot;


void setup()
{
  Particle.variable("TopH", TopH);
  Particle.variable("TopL", TopL);
  Particle.variable("MidH", MidH);
  Particle.variable("MidL", MidL);
  Particle.variable("BotH", BotH);
  Particle.variable("BotL", BotL);
  Particle.variable("ECO-Qtot", Qtot);
}


void loop()
{
  getTemperatures(0);

  Av1 = (TopH + TopL)/2;
  Av2 = (TopL + MidH)/2;
  Av3 = (MidH + MidL)/2;
  Av4 = (MidL + BotH)/2;
  Av5 = (BotH + BotL)/2;

  Q1 = (Av1-Tmin)*110*1.163/1000;
  Q2 = (Av2-Tmin)*90*1.163/1000;
  Q3 = (Av3-Tmin)*90*1.163/1000;
  Q4 = (Av4-Tmin)*90*1.163/1000;
  Q5 = (Av5-Tmin)*110*1.163/1000;
  Qtot = Q1+Q2+Q3+Q4+Q5;

  delay(5000);
}


void getTemperatures(int select)
{
    ds.reset();
    ds.skip(); 
    ds.write(0x44, 0);
    delay(1000);
    ds.reset();

    for (int i=0; i< sizeof(temps)/sizeof(temps[0]); i++)
    {
        switch (select)
        {
            case 0:
                ds.select(addrs0[i]);
                break;
            case 1:
                ds.select(addrs1[i]);
                break;
        }

        ds.write(0xBE,0);

        byte data0 = ds.read();
        byte data1 = ds.read();
        ds.reset();

        if (select == 0)
        {
            int16_t raw = (data1 << 8) | data0;
            celsius = (double)raw * 0.0625;
        }
        else if (select == 1)
        {
            int16_t raw = data0;
            celsius = (double)raw * 0.5;
        }

        *temps[i] = celsius;
    }
}

It is in my opinion simplified as much as possible and it works really perfectly, thanks @ric!
I could not have developed this myself…
:older_man:

4 Likes