Read manual, Particle.subscribe to event issues

I have had a photon running just fine for a days now with code for my BME280 Temperature sensor, now I am trying to combine a few things and am stuck.

I am publishing this from the photon A with the BME280.

  Particle.publish("Temperature in Celsius : ", String(bmeTemperature), 60, PRIVATE);

I have a second photon, call it Photon B, with Neopixels that I wanted to visualize the data with LED’s, I had that running with it’s OWN BME280 connected directly to it to test and make work, now I want to read the temperature data from Photon A, and visualize it on Photon B.

// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_BME280/Adafruit_BME280.h"

// This #include statement was automatically added by the Particle IDE.
// This #include statement was automatically added by the Particle IDE.
#include "neopixel/neopixel.h"

#include "application.h"


SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(ENABLED);


#define PIXEL_PIN D6
#define PIXEL_COUNT 24
#define PIXEL_TYPE WS2812B

//#define SEALEVELPRESSURE_HPA (1013.25)


Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

Adafruit_BME280 bme;


//BME280 maths? 
double tmp;

float bmeTemperature;


void setup() {
    
    Serial.begin(9600);
    while(!Serial.available()) Particle.process();    
    
    // Initialze BME280 Temperature sensor
    if (!bme.begin()) {
		while (1) {}
	}
    Particle.variable("temperature", &tmp, DOUBLE); 
    //Particle.subscribe("Temperature in Celsius : ", String(bmeTemperature));
    strip.begin(); // Initialize the strip 
    strip.show(); // Initialize all pixels to 'off'
    strip.setBrightness(25); // Set brightness limit (value between 0-255)

}


void loop() {
    tmp = (double) bme.readTemperature();
    delay(5000);
    temp_strip();
    delay(200);

}


void temp_strip(){
    int low=10;
    int high=35;

     for(int i=0; i<strip.numPixels(); i++) {
        if(((int)tmp)>=(low+i)) strip.setPixelColor(i, strip.Color(map(i,0,strip.numPixels(),0,255),0,map(i,0,strip.numPixels(),255,0)));
        else strip.setPixelColor(i,strip.Color(0,0,0));
    }
    strip.show();

}

And what exactly is the issue?

2 Likes

First you should put your Particle.xxx() calls in setup() before anything that could take longer than 5sec (e.g. your while() loops) to make sure they get registered with the cloud.

Next, why is that subscribe commented out?

Third, try to use shorter event names (and subscribe filters can just be a beginning part of the event name - aka prefix filter)

Since you didn’t actually state the nature of your problem (or I missed it - but as @Moors7 can’t see it either, it might be missing really :wink: ), this might be the main point:
When publishing PRIVATE events, you need to subscribe to MY_DEVICES in order to get the event triggered.

And Particle.subscribe() expects a function as event handler
https://docs.particle.io/reference/firmware/photon/#particle-subscribe-

3 Likes

Yes I realize the MY_Devices must be in the subscribe, its commented out because it does not work, even with that addition.

I get this error if I uncomment that line.

bmelightring.cpp:44:91: error: no matching function for call to 'CloudClass::subscribe(const char [26], String, int, Spark_Subscription_Scope_TypeDef)'



                                                                                       ^

Have you also got the bit about needing a function?

That's exactly what that error message means.
There is no Particle.subscribe() that takes a String as second parameter.
And usually such an error message comes with a related note that even lists possible candidates that do exist.

That's the sample code from the docs you "read"

see the difference?

If it isn’t simply calling it and using it as literal strings, I have no programming ability to create my own functions or whatever.

Its a damn miracle I can get this far. I thought it would be as simple as publish, and then subscribe to the event.

I need simpler.

@Cloud, it really doesn't get simpler! What you need is to learn and that's why asking questions on the forum is good :wink:

You publish a string from A and catch that string via a function on B that translates that string back into a number to be used.

void myHandler(const char *event, const char *data)
{
  // event will contain "Temperature in Celsius : "
  // data will contain your number as string literal
}

Asking not demanding it to need it simpler!

That right there, ZERO understanding how that works.

what is myHandler?

And I definitely am not demanding anything, simply stating needs, I don’t have what normal people in society do, that empathy does not exist here (aspergers). I am much to literal to read into feelings, I hardly have them.

@Cloud I started from scratch with these microcontrollers about two years ago knowing nothing. Now I’m building stuff that I never thought possible before. Just keep with it and take advantage of the awesome community that is here and you should have no problem achieving your goals.

Persistence is the key :smiley:

If you take a look at the examples, rather than trying to start from scratch, you might have more success. Try editing existing examples, it helps with the understanding.

We are willing to help, that’s why we donate tons of time to this community for members and the great folks at Particle so the only thing we get from this is the gratitude of people and nice support from Particle - that’s what keeps us going.

And makes us slightly prickly when we feel taken for granted.
The knowledge about your “handicap” in that regard does help feeling less used tho’.

So then let’s take that slowly:
If you look at the sample I posted you have

Particle.subscribe("temperature", myHandler);
// or for PRIVATE events
Particle.subscribe("temperature", myHandler, MY_DEVICES);

Where the second parameter is a function (actually a pointer to a function referenced by the function name) that should be called once an event arrives (it can be named whatever, but myHandler is a nice descirptive name since it handles the arrivals of my events).
This function has to obey some rules to be able to be called.
And these are writen in code like this

void myHandler(const char *event, const char *data) 

Which means that the function mustn’t return a value (void) but take two parameters (both strings const char*).

So with your intent in mind the function should look like this

void myHandler(const char *event, const char *data)
{
  bmeTemperature = atof(data);  // convert the incoming string literal to float and put the value in the global variable
}

You might, just for convenience, add a global flag to indicate whenever you received a new event.

2 Likes

So I commented out line 55 Particle.variable function, &tmp which was being used to initialize the strip before using (bmeTemperature), which is the only error left.

I had to lookup atof, is this actually doing what line 65 tmp = (double) bmeTemperature(); used to do? If so I am stabbing in the dark I need to rename that somewhere.

// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_BME280/Adafruit_BME280.h"

// This #include statement was automatically added by the Particle IDE.
// This #include statement was automatically added by the Particle IDE.
#include "neopixel/neopixel.h"

#include "application.h"


SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(ENABLED);


#define PIXEL_PIN D6
#define PIXEL_COUNT 24
#define PIXEL_TYPE WS2812B

//#define SEALEVELPRESSURE_HPA (1013.25)


Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

Adafruit_BME280 bme;


//BME280 maths? 
double tmp;


float bmeTemperature;



void myHandler(const char *event, const char *data)
{
    
  bmeTemperature = atof(data);  // convert the incoming string literal to float and put the value in the global variable
  
}

void setup() {
    
    Serial.begin(9600);
    while(!Serial.available()) Particle.process();    
    
    // Initialze BME280 Temperature sensor
    if (!bme.begin()) {
		while (1) {}
	}
	
	
	Particle.subscribe("Temperature in Celcius", myHandler, MY_DEVICES);
    //Particle.variable("temperature", &tmp, DOUBLE); 
  
    strip.begin(); // Initialize the strip 
    strip.show(); // Initialize all pixels to 'off'
    strip.setBrightness(25); // Set brightness limit (value between 0-255)

}


void loop() {
    tmp = (double) bmeTemperature();
    delay(5000);
    temp_strip();
    delay(200);

}


void temp_strip(){
    int low=10;
    int high=35;

     for(int i=0; i<strip.numPixels(); i++) {
        if(((int)tmp)>=(low+i)) strip.setPixelColor(i, strip.Color(map(i,0,strip.numPixels(),0,255),0,map(i,0,strip.numPixels(),255,0)));
        else strip.setPixelColor(i,strip.Color(0,0,0));
    }
    strip.show();

}

Then you should provide the error message to know what the compiler doesn't like exactly.

Not quite.
tmp = (double)bmeTemperature; would be called type casting (to look up), which is used to "fool" the compiler into believing that the a variable of one type is actually another, but that doesn't translate one type into another.
float and double are compatible types (both numeric values), but strings can't just be type casted into numeric types.
For that you need functions that actually translate the string into it's numeric value (if possible). And atof() (ASCII to float) is such a translator function that takes a string and hands you back the number.

In your line you've got another error.

tmp = (double) bmeTemperature();

The parentheses at the end suggest that bmeTemperature is a function to call instead of a float variable. But you've declared it

float bmeTemperature;

But looking at your code, you could just drop either bmeTemperature or tmp and only use the respective other (which then needs to be a double).

And my initial suggestion still stands

Additionally, I’d make the event name shorter, without blank spaces. “CloudTempPub” or something similar. Blank spaces are horrible in the computing world. They may work, they may not…

Don’t quite understand it yet, but this works, forgive commenting out everywhere.

  


// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_BME280/Adafruit_BME280.h"

// This #include statement was automatically added by the Particle IDE.
// This #include statement was automatically added by the Particle IDE.
#include "neopixel/neopixel.h"

#include "application.h"


SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(ENABLED);


#define PIXEL_PIN D6
#define PIXEL_COUNT 24
#define PIXEL_TYPE WS2812B

//#define SEALEVELPRESSURE_HPA (1013.25)


Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

Adafruit_BME280 bme;


//BME280 maths? 
double tmp;


//float bmeTemperature;

int bmeTemperature;


void myHandler(const char *event, const char *data)
{
    
  bmeTemperature = atof(data);  // convert the incoming string literal to float and put the value in the global variable
  
}

void setup() {
    
    Serial.begin(9600);
    Particle.subscribe("TempCpub", myHandler, MY_DEVICES);
    while(!Serial.available()) Particle.process();    
    
    // Initialze BME280 Temperature sensor
//    if (!bme.begin()) {
//		while (1) {}
//	}
	
	
	
    Particle.variable("TempCpub", &tmp, DOUBLE); 
  
    strip.begin(); // Initialize the strip 
    strip.show(); // Initialize all pixels to 'off'
    strip.setBrightness(25); // Set brightness limit (value between 0-255)

}


void loop() {
    tmp = (double) bmeTemperature;
    delay(5000);
    temp_strip();
    delay(200);

}


void temp_strip(){
    int low=10;
    int high=35;

     for(int i=0; i<strip.numPixels(); i++) {
        if(((int)tmp)>=(low+i)) strip.setPixelColor(i, strip.Color(map(i,0,strip.numPixels(),0,255),0,map(i,0,strip.numPixels(),255,0)));
        else strip.setPixelColor(i,strip.Color(0,0,0));
    }
    strip.show();

}

@Moors7 I took your advice and renamed them shorter and simpler

I know it is probably wrong somewhere, honestly I am just stabbing like a kindergartner putting appropriate shapes into the holes. Trying things until I get fewer and fewer errors, until its diluted enough I can fake it.

You can drop bmeTemperature completely and replace all other occurences of it with tmp.

Like this

#include "Particle.h"
#include "Adafruit_BME280/Adafruit_BME280.h"
#include "neopixel/neopixel.h"

SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(ENABLED);

#define PIXEL_PIN D6
#define PIXEL_COUNT 24
#define PIXEL_TYPE WS2812B
#define PIXEL_LOW 10
#define PIXEL_HIGH 35

Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
Adafruit_BME280 bme;

double tmp;

void myHandler(const char *event, const char *data) {
  tmp = atof(data);  // convert the incoming string literal to float and put the value in the global variable
}

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

    Particle.variable("TempC", tmp);  // don't name the var the same as the event to avoid confusion 
    Particle.subscribe("TempCpub", myHandler, MY_DEVICES);

    while(!Serial.available() && millis() < 60000) Particle.process();    // wait for serial terminal or 60sec timeout

    // Initialze BME280 Temperature sensor
    if (!bme.begin()) while(true) Particle.process();  // block forever but keep cloud connected
	
    strip.begin(); // Initialize the strip 
    strip.show(); // Initialize all pixels to 'off'
    strip.setBrightness(25); // Set brightness limit (value between 0-255)
}

void loop() {
    static uint32_t ms;
    if(millis() - ms < 5000) return; // delay while keeping cloud responsive
    ms = millis();
    temp_strip();
}

void temp_strip() {
    for(int i = 0; i < strip.numPixels(); i++) {
        if(tmp >= (PIXEL_LOW + i)) {
            int col = map(i, 0, strip.numPixels(), 0, 255);
            strip.setPixelColor(i, strip.Color(col, 0, 255-col));
        }
        else {
            strip.setPixelColor(i,strip.Color(0, 0, 0));
        } 
    }
    strip.show();
}