Problem with "not declared in this scope" when to divide into .cpp/.h (DS18B20)

I’m trying to divide a sketch as to make it a bit easier to understand to be able to publish it eventually.
It is part of a bigger software/hardware project where I get temperature readings (for example) with a ESP8266 and send them to a grafana backend.

But back to my problem, I get the error “‘sensor_ds’ was not declared in this scope” when trying to have the OneWire/DallasTemperature in a separate .cpp file instead of in the .ino file. Making me think it was related either to my lacking knowledge of object/constructors or to the IDEs pre-processor playing some tricks. nut after having tied all sort of having a begin function just to having a begin and a empty constructor as well as numerus other alternatives I moved on to the pre-processor and tried having only the libraries in the .ino file and separate .cpp file with what used to be there, as mentioned https://forum.arduino.cc/index.php?topic=97455.012. Issues with the IDE pre-processor.

And now I am starting to run out of ideas, one is that is has something to do with how the DallasTemperature is referencing the OneWire? But now I am just reaching…

I have made an example that showcase my problem and been searching to find a solution but after spending almost the entire day on it I must ask for some help from the fine people of this forum.

The .ino file

#include <Arduino.h>
#include <OneWire.h> // One Wire support 
#include <DallasTemperature.h> //DS18B20
#include "DS18b20Temp.h"

The sketch.cpp file:

#include <Arduino.h>
#include <OneWire.h>            // One Wire support, used in-> 
#include <DallasTemperature.h>  // DS18B20
#include "DS18b20Temp.h"        // Trying to separate this part

DS18b20Temp ds18b20Temp; //Initialize the constructor

void setup() {
  Serial.begin(115200);
  ds18b20Temp.begin();  // Startup of temp sensor
}

void loop() {
  Serial.println("Loop start");
  uint8_t numbers = ds18b20Temp.send_count();
  Serial.println(numbers);
}

The .cpp file containing the portion I want to break out (DS18b20Temp.cpp):

#include "DS18b20Temp.h"
#include <Arduino.h>
#include <OneWire.h> // One Wire support 
#include <DallasTemperature.h> //DS18B20

void DS18b20Temp::begin() {
    OneWire oneWire(TEMP_PIN);
    DallasTemperature sensor_ds(&oneWire);
    sensor_ds.begin(); // 
    sensor_ds.requestTemperatures();
}

uint8_t DS18b20Temp::send_count() {
  uint8_t numbers = 1;//sensor_ds.getDeviceCount(void);
  return numbers;
}

Header file for it(DS18b20Temp.h):

#ifndef _DS18b20Temp_h
#define _DS18b20Temp_h

#define TEMP_PIN 2   // Used to be ONE_WIRE_BUS
#include <Arduino.h>

class DS18b20Temp
{
  protected:
  public:
    void begin();
    uint8_t send_count();

};
#endif

Thanks in advance!

I can't actually see what's wrong from that code, but I rather suspect it's because you declare sensor_ds in your begin method, so if you try to use it anywhere else you'll see that out of scope error. I would expect sensor_ds to be declared as a class member.

Well it always nice to not have made an obvious misstake :wink:

But how would I declare it as a class member?

#ifndef _DS18b20Temp_h
#define _DS18b20Temp_h

#define TEMP_PIN 2   // Used to be ONE_WIRE_BUS
#include <Arduino.h>

class DS18b20Temp
{
  protected:
                   //<--- in this portion?
  public:
    void begin();
    uint8_t send_count();

};
#endif

According to the DallasTemperature.cpp it is a OneWire*.

DallasTemperature::DallasTemperature(OneWire* _oneWire)
{
	setOneWire(_oneWire);
#if REQUIRESALARMS
	setAlarmHandler(NO_ALARM_HANDLER);
#endif
}

The code from your original post compiles for me (I suspect because you have the call to ‘sensor_ds.getDeviceCount(void);’ commented out). But, it’s incorrect. The oneWire instance of the OneWire class and the sensor_ds instance of the DallasTemperature class are local variable to the begin() function. They cease to exist once that function exits.

Try this:

Main Program:

#include <Arduino.h>
#include "DS18b20Temp.h"        // Trying to separate this part

const uint8_t oneWirePin = 2;

DS18b20Temp ds18b20Temp(oneWirePin);

void setup() {
  Serial.begin(115200);
  ds18b20Temp.begin();  // Startup of temp sensor
}

void loop() {
  Serial.println("Loop start");
  uint8_t numbers = ds18b20Temp.send_count();
  Serial.println(numbers);
  delay(1000);
}

DS18b20Temp.h:

#ifndef _DS18b20Temp_h
#define _DS18b20Temp_h

#include <Arduino.h>
#include <OneWire.h> // One Wire support
#include <DallasTemperature.h> //DS18B20

class DS18b20Temp {
public:
 DS18b20Temp(uint8_t p);
 void begin();
 uint8_t send_count();

private:
 OneWire oneWire;
 DallasTemperature sensor_ds;
};
#endif

DS18b20Temp.cpp:

#include "DS18b20Temp.h"

DS18b20Temp::DS18b20Temp(uint8_t p) : oneWire(p), sensor_ds(&oneWire) {
}

void DS18b20Temp::begin() {
    sensor_ds.begin();
    sensor_ds.requestTemperatures();
}

uint8_t DS18b20Temp::send_count() {
  uint8_t numbers = 1;
  numbers = sensor_ds.getDeviceCount();
  return numbers;
}

@gfvalvo Thank you so very much for the solution!

Yes indeed I did for people to try it out and help solve it, but should have explained that with a comment.

I was starting to guess something similar but could not figure out how to get it to be persistent for the entire class.

I think i understand what is happening but not the exact syntax, the is obviously in DS18b20Temp::DS18b20Temp(uint8_t p) : oneWire(p), sensor_ds(&oneWire) {
}

The is a self-constructor? taking the argument p passing it to the function oneWire and the result of that to function sensor_ds, correct?

To read a bit more about it, what would be the correct terminology for this? Specifically the : operator.

And once again thanks for the support this forum offers, top notch. Now I can go and and hopefully share the entirety of the project, both hardware and software soon.

I will shortly post a more useful version of this with some serial printout of this test case.

ursidae:
I think i understand what is happening but not the exact syntax, the is obviously in DS18b20Temp::DS18b20Temp(uint8_t p) : oneWire(p), sensor_ds(&oneWire) {
}

The is a self-constructor? taking the argument p passing it to the function oneWire and the result of that to function sensor_ds, correct?

It is a Constructor for the class.

To read a bit more about it, what would be the correct terminology for this? Specifically the : operator.

The construct is an Initializer List. This happens to be Case #3 in that article.

Okay thanks for the clarification, will read up on it for sure!

ursidae:
I think i understand what is happening but not the exact syntax, the is obviously in DS18b20Temp::DS18b20Temp(uint8_t p) : oneWire(p), sensor_ds(&oneWire) {
}
.
.
taking the argument p passing it to the function oneWire and the result of that to function sensor_ds, correct?

Not quite. The argument 'p' is passed to the constructor for the OneWire class which then constructs the object named oneWire. It's a little confusing since you used a very similar name to the class for your object of that class.

Also, this part .... 'sensor_ds(&oneWire)' passes the address of (aka a pointer to) the newly constructed OneWire object (named oneWire) to the constructor for the DallasTemperature class which then constructs your object of that class named sensor_ds.

Thank you for the clarification, most helpful!