Hi,
I’ve recently migrated my setup from two Photons on my wifi network to a 3G Boron gateway with a Xenon in mesh. The Boron reboots frequently, previously after several days, then several hours, this last time after 20 minutes.
The Xenon is a temperature probe, it publishes a value every 5 mintues. The Boron listens to the Xenon and if needed will turn the heating on or off by turning a servo. During the 20 minutes from flashing new code to the time of the reboot it didn’t actuate the servo so I don’t think I have a power issue. Moreover, the servo and Boron have seperate power supplies.
I’m looking for advice on how to debug this issue. I include my code below for reference. I’m using current firmware and all the reported vitals are healthy.
Boron code (DeviceOS 1.4.2)
Servo servoDial; // create servo object to control a servo
int actualTemp = 120; // variable to store actual temp
int targetTemp = 70; // variable to store target temp
int targetDelta = 10;
int pos = 10; // variable to store the servo position
int Heating = 0;
int servoPositionOn = 175;
int servoPositionOff = 10;
char HeatingStr[8] = "OFF";
char statusMsg[64] = "Empty";
// set to 1 to conserve bandwidth
int ConserveBW = 1;
void setup()
{
// initialise the servo
servoDial.attach(D2); // attaches the servo on the correct pin to the servo object
// This subscribed function allows the Particle to get the temperature
Particle.subscribe("io_temp", gotSalonTemp, MY_DEVICES);
// Expose variables to allow information gathering
Particle.variable("Position", &pos, INT);
Particle.variable("TargetTemp", &targetTemp, INT);
Particle.variable("ActualTemp", &actualTemp, INT);
Particle.variable("Heating", &Heating, INT);
Particle.variable("ConserveBW", &ConserveBW, INT);
// Functions to allow control
Particle.function("ioTarget", setTargetTemp);
Particle.function("ioPosition", setPosition);
Particle.function("ioSaveBandwidth", setBandwidth);
// default to off
servoDial.write(servoPositionOff);
snprintf(statusMsg,64,"%s/%d/%d/Setup !",HeatingStr,actualTemp,targetTemp);
//statusMsg = HeatingStr + "/" + actualTemp + "/" + targetTemp + "/" + "Setup !";
Particle.publish("io_boiler_setup",statusMsg,PRIVATE);
// End of setup
}
void loop()
{
//nothing to do here
}
// Set Bandwidth function will make Particle less busy on the wire
int setBandwidth(String BWValue) {
if (BWValue.toInt() == 1) {
ConserveBW = BWValue.toInt();
} else {
ConserveBW = 0;
}
snprintf(statusMsg,64,"%s/%d/%d/Set Bandwidth %d",HeatingStr,actualTemp,targetTemp,ConserveBW);
Particle.publish("io_boiler_bandwidth",statusMsg,PRIVATE);
return 0;
}
// Set position function will allow for testing and calibrating the servo motor
int setPosition(String posValue) {
pos = posValue.toInt();
snprintf(statusMsg,64,"%s/%d/%d/Move to position %d",HeatingStr,actualTemp,targetTemp,pos);
Particle.publish("io_boiler_position",statusMsg,PRIVATE);
servoDial.write(pos);
return 0;
}
// Set target Temperature
int setTargetTemp(String tempValue) {
// Trying to make foolproof
// Particle.publish("io_target_temp",tempValue);
targetTemp = tempValue.toInt();
if (targetTemp < 101)
{
// In antifreeze mode it is better to heat longer that to continue switching between states, there is a risk of the servo popping out
targetDelta = 10;
} else
{
targetDelta = 3;
}
snprintf(statusMsg,64,"%s/%d/%d/Set new temp !%d",HeatingStr,actualTemp,targetTemp,targetTemp);
Particle.publish("io_boiler_target",statusMsg,PRIVATE);
boilerControlLogic();
return 0;
}
// Subscribed function which receives fetched temperature
void gotSalonTemp(const char *name, const char *data) {
// Important note! -- Right now the response comes in 512 byte chunks.
// This code assumes we're getting the response in large chunks, and this
// assumption breaks down if a line happens to be split across response chunks.
//
actualTemp = String(data).toInt();
if (ConserveBW == 0) {
snprintf(statusMsg,64,"%s/%d/%d/Received:%s",HeatingStr,actualTemp,targetTemp,data);
Particle.publish("io_boiler",statusMsg,PRIVATE);
}
boilerControlLogic();
}
// Turn on heating
void turnOnHeating() {
snprintf(statusMsg,64,"%s/%d/%d/Turning on",HeatingStr,actualTemp,targetTemp);
// statusMsg = HeatingStr + "/" + actualTemp + "/" + targetTemp + "/" + "Turning on";
Particle.publish("io_boiler_on",statusMsg,PRIVATE);
servoDial.write(servoPositionOn);
//Record new state
pos = servoPositionOn;
snprintf(HeatingStr,8,"ON");
Heating = 1;
}
// Turn off heating
void turnOffHeating() {
snprintf(statusMsg,64,"%s/%d/%d/Turning off",HeatingStr,actualTemp,targetTemp);
// statusMsg = HeatingStr + "/" + actualTemp + "/" + targetTemp + "/" + "Turning off";
Particle.publish("io_boiler_off",statusMsg,PRIVATE);
servoDial.write(servoPositionOff);
//Record new state
pos = servoPositionOff;
snprintf(HeatingStr,8,"OFF");
Heating =0;
}
// Logic for turning on and off
// Compares input temperature to targets
int boilerControlLogic() {
if (actualTemp > targetTemp + targetDelta)
{
if(Heating==1) {turnOffHeating();}
} else
{
if (actualTemp < targetTemp)
{
// Too cool
if(Heating==0) {turnOnHeating();}
}
}
return 0;
}
Photon code (DeviceOS 1.4.2)
#include <math.h>
// the value of the 'other' resistor
#define SERIESRESISTOR 10000
// which analog pin to connect
#define THERMISTORPIN A0
// resistance at 25 degrees C
#define THERMISTORNOMINAL 10000
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3977
// the value of the 'other' resistor
#define SERIESRESISTOR 10000
int samples[NUMSAMPLES];
int tempindecimals0 = TEMPERATURENOMINAL;
char publishString[40];
// set to 1 to conserve bandwidth
int ConserveBW = 1;
void setup() {
// register API variable
Particle.variable("temperature", &tempindecimals0, INT);
Particle.variable("ConserveBW", &ConserveBW, INT);
Particle.function("ioSaveBandwidth", setBandwidth);
pinMode(THERMISTORPIN, INPUT);
}
void loop() {
uint8_t i;
float average;
// take N samples in a row, with a slight delay
for (i=0; i< NUMSAMPLES; i++) {
samples[i] = analogRead(THERMISTORPIN);
delay(10);
}
// average all the samples out
average = 0;
for (i=0; i< NUMSAMPLES; i++) {
average += samples[i];
}
average /= NUMSAMPLES;
// convert the value to resistance
average = 4095 / average - 1;
average = SERIESRESISTOR / average;
float steinhart;
steinhart = average / THERMISTORNOMINAL; // (R/Ro)
steinhart = log(steinhart); // ln(R/Ro)
steinhart /= BCOEFFICIENT; // 1/B * ln(R/Ro)
steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
steinhart = 1.0 / steinhart; // Invert
steinhart -= 273.15; // convert to C
tempindecimals0 = int(steinhart*10.0);
snprintf(publishString,40,"%d", tempindecimals0);
Particle.publish("io_temp",publishString, PRIVATE);
if (ConserveBW == 1) {
// Delay 5 minutes
delay(300000);
} else {
// Delay 1 minute
delay(60000);
}
}
// Set Bandwidth function will make Particle less busy on the wire
int setBandwidth(String BWValue) {
if (BWValue.toInt() == 1) {
ConserveBW = BWValue.toInt();
} else {
ConserveBW = 0;
}
return 0;
}