How to transfer data between 2 cores?

Hi, Im looking to make weather monitor that consists of:

  1. Spark Core nr1 with sensors located outside house.
  2. Spark Core nr2 with LCD inside house that displays sensor data from Core 1.

Both Cores are connected to internet, but there is no Core to Core wifi signal (they are too far apart).

What are my options here? I’ve never done anything like this (data transfer to core) so i don’t even know where to begin with.

Have a look in this thread

It’s about a similar project

2 Likes

This might be interesting as well: http://www.hackster.io/maxeust/quantumly-entangled-leds1
The relevants docs are here: http://docs.spark.io/firmware/#spark-publish

Tnx, ill have some reading and lot’s of trial and error ahead of me now :smile:

1 Like

I made a test code (send and receive though single Core since i don’t have second Core atm), but it doesn’t work quite as it is suppose to.

[code]
double c = 1;
int i=0;
void tempHandler(const char *event, const char *data)
{
i++;
Serial.print(event);
Serial.print(", data: ");
if (data)
Serial.println(data);
else
Serial.println(“NULL”);
delay(500);
}

void setup()
{
Spark.variable(“temp”, &c, DOUBLE);
Spark.subscribe(“temperature”, tempHandler, MY_DEVICES);
Serial.begin(9600);
}

void loop()
{
c++;

Spark.publish(“temperature”, String©); // <-- observe STRING

delay(1000);
}[/code]
If i watch serial then it counts temp up to 13 (quite long and irrdic pauses there between) but then core seems to crash (red blinks). What might be the problem?

Red blink might be in SOS pattern or smth. fter that it seems to restart (blinks green and then breeths cyan) but serial doesnt work until i make hard restart.

@qwerty009, at first look I’d suspect String() which might not free its allocated heap space correctly.
To confirm this, just replace String(c) with a constant string and see.

I think you could also drop the delay(500) within the tempHandler since you should only get one event per second, due to delay(1000) in loop.

1 Like

Like this?

[code]double c = 1;
int i=0;
void tempHandler(const char *event, const char *data)
{
i++;
Serial.print(event);
Serial.print(", data: ");
if (data)
Serial.println(data);
else
Serial.println(“NULL”);
}

void setup()
{
Spark.variable(“temp”, &c, DOUBLE);
Spark.subscribe(“temperature”, tempHandler, MY_DEVICES);
Serial.begin(9600);
}

void loop()
{
c++;

Spark.publish(“temperature”, 0); // <-- observe STRING

delay(1000);
}[/code]
Still same behaviour.

Sorry, no. I actually meant more something like

   Spark.publish("temperature", "Test");

Just for safety, could you also put the Serial.begin() before your Spark.subscribe() statement, so that there will be absolutely no way how Serial.print() could happen before Serial.begin().
Due to your MY_DEVICES option, it shouldn’t anway - but who knows.

@qwerty009, you may also be interested in this recent topic:

I’ve now flashed your code on one of my Cores and will try to squash your bug.
So far I found that it is an SOS Hard-Fault (one red blink)


Edit1:
At the moment I at least got rid of the hard fault by removing the Serial.print() statements from the event handler, but the Spark.subscribe() seems very unreliable at the moment.
Maybe @Dave could chime in to explain why after so far over 350 publishes (every two sec) I only got three subscription calls (Chrome view-source does show all published events nicely - so no WiFi/internet trouble)

That`s my code at the moment

#define EVENTNAME "scruffTemp"

double c;
int i;
char msg[16];

void tempHandler(const char *event, const char *data)
{
  i++;
  digitalWrite(D7, !digitalRead(D7));
}
void setup()
{
  long l = millis();
  c = 0;
  i = 0;
 
  pinMode(D7, OUTPUT);
  digitalWrite(D7, HIGH);
    
  Serial.begin(115200);

  // wait for a serial byte or 5sec 
  while(!Serial.available() && (millis()-l) < 5000)
    SPARK_WLAN_Loop();
      
  Spark.subscribe(EVENTNAME, tempHandler);
}

void loop()
{
  c += 1.0;  
  
  sprintf(msg, "%d. Temp %5.2f", i, c);
  Spark.publish(EVENTNAME, msg); 
  
  Serial.print(i);
  Serial.print(" ");
  Serial.println(c);
  Serial.println(msg);
  
  delay(2000);
}

OTA flashing has seized working with this code, too.
Is there something up with the cloud, too may Cores as Christmas presents overwhelming it ;-)?


Edit2:
After I removed the “self-subscription” and scubscribed on another Core to the event of the first it seems to work.
I do get as good as every publish event.


I’ll report back, when I know more :wink:

@qwerty009, I think you’d have to wait for your second Core to arrive or find another way to build and test the two sides of your communication, since this seems that “self-subscription” might be an issue Spark will have to look into.

I’ll tag @Dave, @mdma and @zach for this reason. Maybe they can clarify. Meanwhile I’ll file an issue on the “core-firmware” repo.

Edit: Thanks @mdma, I meant to add that link, but forgot :blush:

Tnx for feedback. I’ll wait for second core to arrive and hope that this issue gets also resolved in near future.

Heya All,

I’m looking into why the self-subscribe might not be working, got that firmware and I’m testing it. Will report back later today hopefully. :slight_smile:

Thanks,
David

Hmm… I modified the code and took out the delay, which I suspected was throwing a wrench into the works. This seems to work much better, but I suspect the pub/sub is causing a race condition in the protocol module on the core, since it’d be getting a double-burst of traffic. So this would need some code to re-add the subscription if it were lost (like during a reconnection)

#define EVENTNAME "scruffTemp"

double c;
int i;
char msg[16];
unsigned int now = 0;

void tempHandler(const char *event, const char *data)
{
  i++;
  digitalWrite(D7, !digitalRead(D7));
}
void setup()
{
  long l = millis();
  c = 0;
  i = 0;
  
  pinMode(D6, INPUT);
  while (digitalRead(D6) == HIGH) {
      Spark.process();
  }
 
  pinMode(D7, OUTPUT);
  digitalWrite(D7, HIGH);
    
  Serial.begin(115200);

  // wait for a serial byte or 5sec 
  while(!Serial.available() && (millis()-l) < 5000)
    SPARK_WLAN_Loop();
      
  now = millis();
  Spark.subscribe(EVENTNAME, tempHandler);
}

void loop()
{
  
  
  if ((millis() - now) > 2000) {
      c += 1.0;  
      sprintf(msg, "%d. Temp %5.2f", i, c);
      Spark.publish(EVENTNAME, msg);
      now = millis();
      
      Serial.print(i);
      Serial.print(" ");
      Serial.println(c);
      Serial.println(msg);
  }
  
  //delay(2000);
}

Now that i received my second Core i wrote this code (Core that measures and then sends temp value to cloud):

[code]// This #include statement was automatically added by the Spark IDE.
#include “OneWire/OneWire.h”

// This #include statement was automatically added by the Spark IDE.
#include “spark-dallas-temperature/spark-dallas-temperature.h”
#define EVENTNAME "temperatuur"
DallasTemperature dallas(new OneWire(D6));

double celsius = 1;
unsigned int now = 0;

void setup()
{
Serial.begin(9600);
dallas.begin();
now = millis();
}

void loop()
{
dallas.requestTemperatures();
double celsius = dallas.getTempCByIndex( 0 );

if ((millis() - now) > 2000) {
Spark.publish(EVENTNAME, String(celsius, 1)); // <-- observe STRING
Serial.print("Temp (andurplaadi serial): "); Serial.println(celsius) ;
now = millis();
}
}[/code]

It seems to work OK (uploads data) but there is this thing again that i can’t reflash Core once i upload this code.

Hi,

Here is code that gets temp value from cloud and displays it:

// This #include statement was automatically added by the Spark IDE.
#include "TimeAlarms/TimeAlarms.h"

// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_mfGFX/Adafruit_mfGFX.h"

// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_ILI9341/Adafruit_ILI9341.h"

#define EVENTNAME "temperatuur"

char displayText[64];

Adafruit_ILI9341 tft = Adafruit_ILI9341(A2, A1, A0);

float minTemp = 100;
float maxTemp = -100;
float hetkeTemp = 0;

void tempHandler(const char *event, const char *data)
{
    hetkeTemp = atof(data);
    if(hetkeTemp>-40 && hetkeTemp <50){
        if (minTemp>hetkeTemp){
            minTemp=hetkeTemp;
        }
        if (maxTemp<hetkeTemp){
            maxTemp=hetkeTemp;
        }
    
    
        Serial.println(data);
        tft.setRotation(1);
        tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
        tft.setTextSize(8);
        tft.setCursor(40,40);
        if(hetkeTemp>0){tft.print("+");} 
        tft.print(hetkeTemp,1); 
        tft.setTextSize(5);
        tft.setCursor(30,120);
        tft.print("MAX ");
        if(maxTemp>0){tft.print("+");}
        tft.print(maxTemp,1); 
        tft.setTextSize(5);
        tft.setCursor(30,170);
        tft.print("MIN ");
        if(minTemp>0){tft.print("+");}
        tft.print(minTemp,1); 
    }
  
  
  
  

}

void setup() {
    Time.zone(+2);
    Alarm.alarmRepeat(23,59,59, MidnightAlarm);  
    Serial.begin(9600);
    Spark.subscribe(EVENTNAME, tempHandler);
    tft.begin();
    tft.fillScreen(ILI9341_WHITE);

}

void loop() {
   Alarm.delay(1000); 


}

void MidnightAlarm(){
    float minTemp = hetkeTemp;
    float maxTemp = hetkeTemp;   
}

Dave previously noted that delay() can’t be used, it would lead to spark crashing. With Timealarms library i have to use Alarm.delay(); without it library doesn’t function. But it again makes my code unresponsive here. I haven’t had time to check exactly how long it runs but it pretty fast stops to refresh data on LCD.
Can anyone suggest any workaround or fix?

Hi @qwerty009

I would move the bulk of your code in tempHandler to loop() and just have tempHandler set hetkeTemp and a boolean (or increment an int) so that you can detect that the value has changed in loop() where you would clear the boolean or remember the last int. That way you are doing less work in the asynchronously called subscribe handler and if it happens to get called again before you can service it, it will not be a problem and the old data just gets overwritten with new data.

You can also call Alarm.delay(0); since under the hood it just waits and calls the internal method serviceAlarms().

Hi,

Do you mean like this:

// This #include statement was automatically added by the Spark IDE.
#include "TimeAlarms/TimeAlarms.h"

// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_mfGFX/Adafruit_mfGFX.h"

// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_ILI9341/Adafruit_ILI9341.h"

#define EVENTNAME "temperatuur"

char displayText[64];

Adafruit_ILI9341 tft = Adafruit_ILI9341(A2, A1, A0);

float minTemp = 100;
float maxTemp = -100;
float hetkeTemp = 0;
int update = 0;
String timeStr;

void tempHandler(const char *event, const char *data)
{

    if (update == 0){
        update = 1;
        hetkeTemp = atof(data);
        Serial.println(data);
    }
  
  
  

}

void setup() {
    Time.zone(+2);
    Alarm.alarmRepeat(23,59,59, MidnightAlarm);  
    Serial.begin(9600);
    Spark.subscribe(EVENTNAME, tempHandler);
    tft.begin();
    tft.fillScreen(ILI9341_WHITE);

}

void loop() {
    if(hetkeTemp>-40 && hetkeTemp <50 && update == 1){
        if (minTemp>hetkeTemp){
            minTemp=hetkeTemp;
        }
        if (maxTemp<hetkeTemp){
            maxTemp=hetkeTemp;
        }
        update = 0;
    
        tft.setRotation(1);
        tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
        tft.setTextSize(8);
        tft.setCursor(40,30);
        if(hetkeTemp>0){tft.print("+");} 
        tft.print(hetkeTemp,1); 
        tft.setTextSize(5);
        tft.setCursor(30,120);
        tft.print("MAX ");
        if(maxTemp>0){tft.print("+");}
        tft.print(maxTemp,1); 
        tft.setTextSize(5);
        tft.setCursor(30,170);
        tft.print("MIN ");
        if(minTemp>0){tft.print("+");}
        tft.print(minTemp,1); 
        tft.setTextSize(2);
        tft.setCursor(110,222);
        digitalClockDisplay();
    }
  
     Alarm.delay(0); 

}

void MidnightAlarm(){
    minTemp = hetkeTemp;
    maxTemp = hetkeTemp;   
}

  void digitalClockDisplay()
    {

          
          
         timeStr = "";
        if(Time.hour()<10){timeStr +=" ";}
        timeStr += Time.hour();
        timeStr += ":";
        if(Time.minute()<10){timeStr +="0";}
        timeStr += Time.minute();
        timeStr += ":";
        if(Time.second()<10){timeStr +="0";}
        timeStr += Time.second();
        timeStr += "";
        tft.print(timeStr);
            

    }

Will let you know in morning how it’s holding up.

Bad news, it has frozen again :confused:
It’s breathing cyan and i can reflash it but it doesn’t update LCD with fresh data. It’s like tempHandler is freezing for some reason.

I’ve kinda gave up on Spark Subscribe/publish and thought to try to upload to Thingspeak website with Core 1 and read from there with Core 2.

Core that is reading and displaying data randomly restarts, best i’ve had is 12h uptime. It bothers me because Min/Max temps of last 24h won’t be displayed properly. I only get readings since last restart.

My code is following:

// This #include statement was automatically added by the Spark IDE.
#include "HttpClient/HttpClient.h"

// This #include statement was automatically added by the Spark IDE.
#include "TimeAlarms/TimeAlarms.h"

// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_mfGFX/Adafruit_mfGFX.h"

// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_ILI9341/Adafruit_ILI9341.h"



//char displayText[64];

Adafruit_ILI9341 tft = Adafruit_ILI9341(A2, A1, A0);

float minTemp = 100;
float maxTemp = -100;
float hetkeTemp = 0;
int update = 0;
//int i=0;
String timeStr;
String timeMax;
String timeMin;


unsigned int uptime = 0;

HttpClient http;

// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
      { "Content-Type", "application/json" },
     // { "Accept" , "application/json" },
    { "Accept" , "*/*"},
    { NULL, NULL } // NOTE: Always terminate headers will NULL
};

http_request_t request;
http_response_t response;


  
  
  



void setup() {
    Time.zone(+2);
    Alarm.alarmRepeat(01,00,00, MidnightAlarm);  
    Alarm.timerRepeat(10, Repeats);
   // Serial.begin(9600);
    tft.begin();
    tft.fillScreen(ILI9341_WHITE);

}

void loop() {
        
    if(hetkeTemp>-40 && hetkeTemp <50 && update == 1){
        if (minTemp>hetkeTemp){
           
            minTemp=hetkeTemp;
            timeMin = "";
            if(Time.hour()<10){timeMin +=" ";}
            timeMin += Time.hour();
            timeMin += ":";
            if(Time.minute()<10){timeMin +="0";}
            timeMin += Time.minute();
        }
        if (maxTemp<hetkeTemp){
            
            maxTemp=hetkeTemp;
            timeMax = "";
            if(Time.hour()<10){timeMax +=" ";}
            timeMax += Time.hour();
            timeMax += ":";
            if(Time.minute()<10){timeMax +="0";}
            timeMax += Time.minute();
        }
            
        uptime=millis()/1000/60;

        tft.setRotation(1);
        tft.setTextColor(ILI9341_BLACK, ILI9341_WHITE);
        
        tft.setTextSize(2);
        tft.setCursor(160,3);
        tft.print(uptime);
        
        tft.setTextSize(8);
        tft.setCursor(40,30);
        if(hetkeTemp>0){tft.print("+");} 
        tft.print(hetkeTemp,1); 
        
        tft.setTextSize(3);
        tft.setCursor(40,120);
        tft.print("MAX ");
        tft.setTextSize(2);
        tft.setCursor(40,145);
        tft.print(timeMax);
        tft.setCursor(150,120);
        tft.setTextSize(5);
        if(maxTemp>0){tft.print("+");}
        tft.print(maxTemp,1); 
        
        tft.setTextSize(3);
        tft.setCursor(40,170);
        tft.print("MIN ");
        tft.setTextSize(2);
        tft.setCursor(40,195);
        tft.print(timeMin);
        tft.setCursor(150,170);
        tft.setTextSize(5);
        if(minTemp>0){tft.print("+");}
        tft.print(minTemp,1); 
        
        tft.setTextSize(2);
        tft.setCursor(110,222);
        tft.print(timeStr);
        
        update = 0;
    }

    Alarm.delay(0);

}


void Repeats(){



    request.hostname = "api.thingspeak.com";
    request.port = 80;
    request.path = "/channels/24877/fields/1/last.json?key=GOKBGDF6332V45P3";
    http.get(request, response, headers);

    if(response.status == 200){

        String web = response.body;
        String aeg2 = web.substring(28,34);
        String aeg1 = web.substring(26,28);
        int gmt = atof(aeg1.c_str());
        int tund = gmt + 2;
        
        timeStr = "";
        timeStr += tund;
        timeStr += aeg2;
        timeStr += "";
    
        int last = web.lastIndexOf('"');
        int previous = web.lastIndexOf('"', last - 1 );
        String result = web.substring(previous+1, last); 
        hetkeTemp = atof(result.c_str());
      
        update = 1;
    }
}


void MidnightAlarm(){
    
    minTemp = hetkeTemp;
    maxTemp = hetkeTemp;
    Spark.syncTime();

}



Maybe i’m not using strings properly or doing smth wrong with http library?
I’d appreciate if you could point me into right direction.