Hi,
I am having trouble with a node. It is a combined Dallas temperature sensor with a relay.
Everything works fine, but after about a day the node starts to behave weird. Sketch attached.
Once it kept on sending the temperature, but did not react to requests to switch the relay anymore.
A power cycle did not help, maybe some capacitors were not fully empty, another power cycle and everything was back to normal.
Another time the same thing happened: The node kept sending the temperatures, but no reaction on the relay.
Another time it failed like this: It kept sending the same temperature over and over again, the true temperature was definitely different (so it was not reading the temperature from the Dallas). It just sent the same temperature, in some strange regular interval, every 7 minutes or so. No matter that the sketch only sends the temperature if it is different from the previous one. Also no reaction on the relay.
I do not know what happens, the node somehow works and operates and sends temperatures, but somehow gets confused. The issue is reproducible it seems, I just need to let it run for 24 hours or more.
Any ideas? Anything wrong in the sketch? Maybe some variable or number that is overflowing? Or the time or the Atmega (millis)?
It is a self built node with an Atmega328p running at 8 MHz with the internal clock. I have built other nodes like this some with 1 MHz that read the temperature around the house, all working fine. But totally different sketches.
Thanks very much in advance for any ideas!
// if you uncomment this, you can get test and debug updates about everything the sensor is doing by using the serial monitor tool.
//#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24 // A 2.4Ghz transmitter and receiver, often used with MySensors.
// #define MY_RF24_PA_LEVEL RF24_PA_MIN // This sets a low-power mode for the radio. Useful if you use the verison with the bigger antenna, but don't want to power that from a separate power source. It can also fix problems with fake Chinese versions of the radio.
// #define MY_RADIO_RFM69 // 433Mhz transmitter and reveiver.
// Choose if you want this sensor to also be a repeater.
// #define MY_REPEATER_FEATURE // Just remove the two slashes at the beginning of this line to also enable this sensor to act as a repeater for other sensors. If this node is on battery power, you probably shouldn't enable this.
// Are you using this sensor on battery power?
// #define BATTERY_POWERED // Just remove the two slashes at the beginning of this line if your node is battery powered. It will then go into deep sleep as much as possible. While it's sleeping it can't work as a repeater!
//#define MY_RF24_PA_LEVEL RF24_PA_LOW
#define MY_PARENT_NODE_ID 99
#define MY_PARENT_NODE_IS_STATIC
#define MY_NODE_ID 8
#define MY_BAUD_RATE 9600
// LIBRARIES (in the Arduino IDE go to Sketch -> Include Library -> Manage Libraries to add these if you don't have them installed yet.)
#include <SPI.h>
#include <MySensors.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#define RELAY_1 4 // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
#define NUMBER_OF_RELAYS 1 // Total number of attached relays
#define RELAY_ON 1 // GPIO value to write to turn on attached relay
#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
//Added this nteger to avoid stupid collect2.exe: error: ld returned 5 exit status.
//It seems adding one or removing one (or plenty) solves the error.
//int stupidinteger=0;
//int stupidintegertwo=0;
//int stupidintegerthree=0;
// VARIABLES YOU CAN CHANGE
#define COMPARE_TEMP 1 // Send temperature only if changed? 1 = Yes 0 = No. Can save battery.
#define ONE_WIRE_BUS 7 // Digital pin where Dallas sensor(s) is/are connected.
#define maxAttachedDS18B20 16 // Maximum amount of teperature sensors you can connect to this arduino (16).
unsigned long measurementInterval = 9250; // Time to wait between reads (in milliseconds).
//float tempThreshold = 0.1; // How big a temperature difference has to be before an update is sent. Makes the sensor less precise, but also less jittery, and can save battery.
//VARIABLES YOU PROBABLY SHOULDN'T CHANGE
#define TEMP_CHILD_ID 0 // for MySensors. Within this node each sensortype should have its own ID number.
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature.
float lastTemperature[maxAttachedDS18B20]; // creates an array to hold the previous temperature measurements for each possible sensor.
int numSensors = 0; // variable to contain the number of found attached sensors.
unsigned long measurementSleepTime = 0; // variable to store the calculated Sleep time if the node is battery powered.
bool metric = true; // Variable that stores if the sensor will output the temperature in Fahrenheit of Celsius. The gateway sends this preference to the node.
bool receivedConfig = false; // This is not used in the code, but perhaps MySensors requires this?
// Mysensors settings
MyMessage msg(TEMP_CHILD_ID,V_TEMP); // Sets up the message format that we'l be sending to the MySensors gateway later. The first part is the ID of the specific sensor module on this node. The second part tells the gateway what kind of data to expect.
void before()
{
sensors.begin(); // Startup up the OneWire library. It allows multiple sensors to talk over one wire (one pin).
for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS; sensor++, pin++) {
// Then set relay pins in output mode
pinMode(pin, OUTPUT);
// Set relay to last known state (using eeprom storage)
digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF);
}
}
void setup()
{
for(int i=0; i<maxAttachedDS18B20; i++)
{
lastTemperature[i] = 0; //Pre-filling array with 0's.
}
sensors.setWaitForConversion(false); // requestTemperatures() will not block current thread
#ifdef BATTERY_POWERED // If the node is batter ypowered, we'll let Sleep take over the scheduling.
measurementSleepTime = measurementInterval;
measurementInterval = 0; // When the Arduino is asleep, millis doesn't increment anymore (time stops as it were). To fix this, we'll set the measurement interval time to 1, so that when the arduino wakes up it will immediately try to measure again.
#endif
//Serial.begin(115200); // for serial debugging.
//Serial.println("Hello world, I am a sensor node.");
}
void presentation()
{
// Send the sketch version information to the gateway and Controller
sendSketchInfo("Maischen relay and Dallas", "1.0");
for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS; sensor++, pin++) {
// Register all sensors to gw (they will be created as child devices)
present(sensor, S_BINARY);
}
numSensors = sensors.getDeviceCount(); // Fetch the number of attached temperature sensors
for (int i=0; i<numSensors && i<maxAttachedDS18B20; i++) {
present(i, S_TEMP);
}
}
void loop()
{
// Fetch temperatures from Dallas sensors
sensors.requestTemperatures();
// query conversion time and sleep until conversion completed
int16_t conversionTime = millisToWaitForConversion(sensors.getResolution());
// sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater)
// Serial.print("Library");
// Serial.print(" says its conversion time is ");
// Serial.print(conversionTime);
// Serial.println(" ms");
wait(conversionTime);
// Read temperatures and send them to controller
for (int i=0; i<numSensors && i<maxAttachedDS18B20; i++) {
// Fetch and round temperature to one decimal
float temperature = static_cast<float>(static_cast<int>((getControllerConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;
// Serial.print("Sensor #");
// Serial.print(i);
// Serial.print(" says it is ");
// Serial.print(temperature);
// Serial.println(" degrees");
// Only send data if temperature has changed and no error
#if COMPARE_TEMP == 1
if (lastTemperature[i] != temperature && temperature != -127.00 && temperature != 85.00) {
#else
if (temperature != -127.00 && temperature != 85.00) {
#endif
Serial.print(temperature - lastTemperature[i]);
Serial.print("Sending the new temperature to the gateway.\n");
// Send in the new temperature
send(msg.setSensor(i).set(temperature,1));
// Save new temperatures for next compare
lastTemperature[i]=temperature;
}
// else {
// Serial.print(temperature - lastTemperature[i]);
// Serial.print("- difference too small, so not sending the new measurement to the gateway.\n");
// }
}
wait(measurementInterval);
}
// This function helps to avoid a problem with the latest Dallas temperature library.
int16_t millisToWaitForConversion(uint8_t bitResolution)
{
switch (bitResolution)
{
case 9:
return 94;
case 10:
return 188;
case 11:
return 375;
default:
return 750;
}
}
void receive(const MyMessage &message)
{
// We only expect one type of message from controller. But we better check anyway.
if (message.type==V_STATUS) {
// Change relay state
digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
// Store state in eeprom
saveState(message.sensor, message.getBool());
// Write some debug info
//Serial.print("Incoming change for sensor:");
//Serial.print(message.sensor);
//Serial.print(", New status: ");
//Serial.println(message.getBool());
}
}