Node only works for a few days
-
it looks like the node lost connection to the gateway.
Had the same issue.
Had to add a repeater between the node and gateway.
Hopefully someone else knows a better solution.Thank you for looking.
I hope not a repeater is needed. They are only 2-3 meters apart. And that don't explain why it works for a few days after a restart.
I have capacitors on both node and gateway, so that should not be a problem either. -
My wild guess would be a memory leak in the code. Turning on debug uses more memory so it takes less time to fail.
-
First switch your gateway to 2.1.0 stable.
I think sensors.begin must be in setup not in loop.
And I think you have perhaps TX problem on gateway side (after reading logs).
Retry with 2.1.0 on both sides, compile node sketch with sensors.begin in setup, turn on log on node and gw.
When you have failure, try to reboot only gateway and wait until node try to find parent. Make the same test but this time reboot only node. -
Thank you for looking.
I hope not a repeater is needed. They are only 2-3 meters apart. And that don't explain why it works for a few days after a restart.
I have capacitors on both node and gateway, so that should not be a problem either. -
First switch your gateway to 2.1.0 stable.
I think sensors.begin must be in setup not in loop.
And I think you have perhaps TX problem on gateway side (after reading logs).
Retry with 2.1.0 on both sides, compile node sketch with sensors.begin in setup, turn on log on node and gw.
When you have failure, try to reboot only gateway and wait until node try to find parent. Make the same test but this time reboot only node.@Fabien said:
First switch your gateway to 2.1.0 stable.
I think sensors.begin must be in setup not in loop.
And I think you have perhaps TX problem on gateway side (after reading logs).
Retry with 2.1.0 on both sides, compile node sketch with sensors.begin in setup, turn on log on node and gw.
When you have failure, try to reboot only gateway and wait until node try to find parent. Make the same test but this time reboot only node.Will try this first. To me it feels that if it was something wrong with the hardware in some way it would happen right away, not only after a few days.
But I'll start with this before I consider to buy new hardware.
-
I had a similar problem with the control of a heating mixer and three dallas sensors. I solved the problem with:
- replacement of the relays with solid state relays
- moved conttroller more in distance of the high voltage parts
I also added a watchdog and a reboot mechanism in case of sensor problems.
Maybe this sketch can give you an inspiration: (work in progress, MYS-Part not tested in depth)
// Enable debug prints to serial monitor //#define MY_DEBUG // in Mysensors #define EN_DEBUG // in this sketch //#define NO_MYS // ohne Mysensors Unterstützung? //#define SIMULATION #define NO_AC_DETECT // ohne AC sensor #define NO_RTC // RTC nur zusammen mit Mysensors #ifdef NO_MYS #ifndef NO_RTC #define NO_RTC #endif #endif #ifdef SIMULATION // für Simulation ohne Sensoren #define SIMULATE_VOR 35 #define SIMULATE_RUE 30 #define SIMULATE_ZU 65 #ifdef SIMULATE_VOR #warning Achtung! Keine Echtentemperaturmessungen -> Simulation #endif #ifdef SIMULATE_RUE #warning Achtung! Keine Echtentemperaturmessungen -> Simulation #endif #ifdef SIMULATE_ZU #warning Achtung! Keine Echtentemperaturmessungen -> Simulation #endif #endif #define START_TARGET_TEMP 40 #define EEPROM_TARGET_TEMP 900 // Save Porisiton. It is above the Mysensors range of lib 2.1 #define EEPROM_POWERSTATE 902 // Save Porisiton. It is above the Mysensors range of lib 2.1 #define MAX_TEMP 50 #define VORLAUF 0 #define RUECKLAUF 1 #define ZULAUF 2 #define PUMPE 0 #define MISCHER_ZU 1 #define MISCHER_AUF 2 #define POWERLED 7 // 8. LED #define TEMPDOWNLED 5 // 6. Led #define TEMPUPLED 6 // 7. Led #ifndef NO_AC_DETECT #define BUDERUSLED 4 // 5. Led #endif #define RETRY_TIMEOUT_PUMP 2*60*1000UL // alle 2 Minuten testen, ob Vorlauf nicht besser (5 Sekunden pumpen) #define REGULATION_TIMEOUT_PUMP 30*1000UL // 30 Sekunden warten nach neuer Einstellung #define PROBE_TIMEOUT_PUMP 5*1000UL // 5 Sekunden Pumpe für Test einschalten, wenn Zulauf zu kalt #define BUDERUS_PIN 3 // Buderus Powererkennung Pumpe auf PIN 3 #ifndef SIMULATION #define MISCHER_RESET_TIME 120*1000UL // 2 Minuten bis Nullstellung #else #define MISCHER_RESET_TIME 10*1000UL // 10 Sekunden bis Nullstellung nei Simulation #endif #ifdef EN_DEBUG #define DEBUG_PRINT(x) Serial.print (x) #else #define DEBUG_PRINT(x) #endif #ifdef EN_DEBUG #define DEBUG_PRINTLN(x) Serial.println (x) #else #define DEBUG_PRINTLN(x) #endif #ifndef NO_MYS // Radio Configuration #define MY_TRANSPORT_WAIT_READY_MS (10000ul) #define MY_RADIO_RFM69 #define MY_RFM69_FREQUENCY RF69_868MHZ #define MY_RFM69_NETWORKID 13 #define MY_RFM69_ENABLE_ENCRYPTION #define MY_NODE_ID 168 //#define MY_IS_RFM69HW #endif #include <Arduino.h> #include <avr/wdt.h> #include <EEPROM.h> #include <MemoryFree.h> #ifndef NO_MYS #define MIN_REPORT_INTERVAL 5 * 60 * 1000L // mindestens alle 5 Minuten melden #include <SPI.h> #include <MySensors.h> #include <Time.h> //http://www.arduino.cc/playground/Code/Time #include <Timezone.h> //https://github.com/JChristensen/Timezone #include <TimeLib.h> //Central European Time (Frankfurt, Paris) TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; //Central European Standard Time Timezone CE(CEST, CET); bool timeReceived = false; unsigned long lastUpdate = 0, lastRequest = 0; #endif #ifndef NO_RTC #include <DS3232RTC.h> // A DS3231/DS3232 library #endif #define MAX_LEDS 8 byte lastButtonState = 0; #define RELAY_ON HIGH #define RELAY_OFF LOW #define RELAY_1 A0 // Arduino Digital I/O pin number for first relay (second on pin+1 etc) #define NUMBER_OF_RELAYS 4 // Total number of attached relays boolean ledState[MAX_LEDS] = { false, false, false, false, false, false, false, false }; boolean relState[NUMBER_OF_RELAYS] = { false, false, false, false }; #include <TM1638.h> #include <DallasTemperature.h> #include <OneWire.h> #define ONE_WIRE_BUS 6 // Pin where dallase sensor is connected #define TEMPERATURE_PRECISION 9 #define MAX_ATTACHED_DS18B20 3 //28B404080000804A DeviceAddress Probe01 = { 0x28, 0xB4, 0x04, 0x08, 0x00, 0x00, 0x80, 0x4A }; //28C606080000803F DeviceAddress Probe02 = { 0x28, 0xC6, 0x06, 0x08, 0x00, 0x00, 0x80, 0x3F }; //28750808000080C3 DeviceAddress Probe03 = { 0x28, 0x75, 0x08, 0x08, 0x00, 0x00, 0x80, 0xC3 }; 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. int numSensors = 0; int lastTemperature[MAX_ATTACHED_DS18B20] = { -100, -100, -100 }; int16_t conversionTime; unsigned long previousTempMillis = -1; static unsigned long nowms = millis(); // update at start of loop() // define LCD module TM1638 ledModule(8, 9, 7); int displayInfo = -1; unsigned long previousDisplayMillis = 0; int targetTemp = START_TARGET_TEMP; #ifdef SIMULATION bool powerOn = true; #ifndef NO_AC_DETECT bool powerOnBuderus = true; #endif #else bool powerOn = false; #ifndef NO_AC_DETECT bool powerOnBuderus = false; #endif #endif bool resetMischer = true; // mischer zuerst in Nullstellung #ifndef NO_AC_DETECT bool testStateBuderus = false; unsigned long lastResetBuderus = -1; #endif #ifndef NO_MYS // Initialize messages MyMessage msgTemp(0, V_TEMP); MyMessage msgStatus(0, V_STATUS); MyMessage msgTargetTemp(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS, V_HVAC_SETPOINT_HEAT); MyMessage msgPower(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 1, V_STATUS); #ifndef NO_AC_DETECT MyMessage msgPowerBuderus(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 2, V_STATUS); #endif MyMessage msgDebug(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 3, V_TEXT); #endif // the setup function runs once when you press reset or power the board void setup() { DEBUG_PRINTLN(F("Starte setup")); wdt_enable(WDTO_8S); Serial.begin(115200); #ifndef NO_RTC // the function to get the time from the RTC setSyncProvider(RTC.get); #endif #ifndef NO_MYS // Request latest time from controller at startup requestTime(); #endif // Zieltemperatur aus EERPOM lesem: targetTemp = EEPROM.read(EEPROM_TARGET_TEMP); if ((targetTemp < 30) || (targetTemp > MAX_TEMP)) { targetTemp = START_TARGET_TEMP; EEPROM.write(EEPROM_TARGET_TEMP, targetTemp); } int state = EEPROM.read(EEPROM_POWERSTATE); if (state == 0) { powerOn = false; } else powerOn = true; #ifndef NO_AC_DETECT // Buderuserkennung auf PIN3 attachInterrupt(digitalPinToInterrupt(BUDERUS_PIN), buderusSet, CHANGE); testStateBuderus = false; lastResetBuderus = millis(); #ifndef NO_MYS send(msgPowerBuderus.set(powerOnBuderus)); #endif #endif // Relayausgänge initialisiern 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, RELAY_OFF); } // Dallas Temperatursensoren sensors.begin(); sensors.setWaitForConversion(false); numSensors = sensors.getDeviceCount(); DEBUG_PRINT(F("Dallas Sensoren ")); DEBUG_PRINTLN(numSensors); DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address for (int i = 0; i < numSensors; i++) { wdt_reset(); // Search the wire for address if (sensors.getAddress(tempDeviceAddress, i)) { DEBUG_PRINT(F("Found device ")); #ifdef EN_DEBUG Serial.print(i, DEC); #endif DEBUG_PRINT(F(" with address: ")); printAddress(tempDeviceAddress); DEBUG_PRINTLN(); DEBUG_PRINT(F("Setting resolution to ")); #ifdef EN_DEBUG Serial.println(TEMPERATURE_PRECISION, DEC); #endif // set the resolution to 12 bit (Each Dallas/Maxim device is capable of several different resolutions) sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION); DEBUG_PRINT(F("Resolution actually set to: ")); #ifdef EN_DEBUG Serial.print(sensors.getResolution(tempDeviceAddress), DEC); #endif DEBUG_PRINTLN(); } else { DEBUG_PRINT(F("Found ghost device at ")); #ifdef EN_DEBUG Serial.print(i, DEC); #endif DEBUG_PRINT(F(" but could not detect address. Check power and cabling")); } } wdt_reset(); sensors.requestTemperatures(); // query conversion time and sleep until conversion completed conversionTime = sensors.millisToWaitForConversion(sensors.getResolution()); } /*****************************************************/ // the loop function runs over and over again forever void loop() { nowms = millis(); #ifndef NO_MYS // If no time has been received yet, request it every 10 second from controller // When time has been received, request update every hour if ((!timeReceived && (nowms - lastRequest) > (10UL * 1000UL)) || (timeReceived && (nowms - lastRequest) > (60UL * 1000UL * 60UL))) { // Request time from controller. DEBUG_PRINTLN("requesting time"); requestTime(); lastRequest = nowms; } #endif wdt_reset(); #ifndef NO_AC_DETECT readAC(); #endif readTemp(); readButtons(); updateDisp(); // Temperaturen senden #ifndef NO_MYS sendTemp(); #endif // Kontroller control(); // Loop 2x pro Sekunde ist aureichend unsigned long loopTime = millis() - nowms; if (loopTime < 450) { #ifdef NO_MYS delay (500 - loopTime); #else wait (500 - loopTime); #endif } } // end loop /**************************************************************/ // Steuerung void control() { wdt_reset(); static unsigned long lastPumpTest = 0; static unsigned long lastRegulation = -REGULATION_TIMEOUT_PUMP; static unsigned long resetStart = 0; // wann wurde die Rücksetzung des Mischers gestartet static bool lastPower = powerOn; static float moveSeconds = 0.0; // Zeiten für Stellmotor Mischer // controllerState // 0 initialized // 1 Pumpe für kurzen test aktiviert, warten auf Timeout für Deaktivierung // 2 in der Regelung, warten auf Timeout für Deaktivierung // 3 in Ausganglage fahren static int controllerState = 0; // Emergency if (lastTemperature[VORLAUF] > MAX_TEMP) { if (resetStart == 0) { if (relState[PUMPE]) { DEBUG_PRINT(F("Zu heiss. Emergency Mischer schliessen")); DEBUG_PRINTLN(lastTemperature[VORLAUF]); } closeMischer(); controllerState = 0; return; } } // Temperatur noch nicht gelesen; if (lastTemperature[VORLAUF] == -100) return; // Fehler mit den Sensoren if ((lastTemperature[VORLAUF] < 0) || (lastTemperature[VORLAUF] > 100) || (lastTemperature[RUECKLAUF] < 0) || (lastTemperature[RUECKLAUF] > 100) || (lastTemperature[ZULAUF] < 0) || (lastTemperature[ZULAUF] > 100)) { relState[PUMPE] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; // Test //powerOn = false; #ifndef NO_MYS //send(msgPower.set(powerOn)); #endif controllerState = 0; DEBUG_PRINTLN(F("Fehler mit den Sensoren, Temperaturen unter 0 oder über 100. Poweroff!")); return; } if (resetMischer) { DEBUG_PRINTLN(F("Mischer initialisieren")); closeMischer(); resetStart = millis(); resetMischer = false; controllerState = 0; return; } if (resetStart > 0) { if ((millis() - resetStart) > MISCHER_RESET_TIME) { DEBUG_PRINTLN(F("Mischer fertig initialisiert")); relState[MISCHER_ZU] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; ledState[MISCHER_ZU] = relState[MISCHER_ZU]; resetStart = 0; controllerState = 0; } return; } // wenn ausser Betrieb -> verlassen; if (powerOn == false) { if (lastPower == false) return; DEBUG_PRINTLN("Go to power off state"); #ifndef NO_MYS send(msgPower.set(powerOn)); #endif lastPower = false; relState[PUMPE] = false; relState[MISCHER_ZU] = false; relState[MISCHER_AUF] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; controllerState = 0; EEPROM.write(EEPROM_POWERSTATE, 0); return; } //DEBUG_PRINTLN("a"); lastPower = true; switch (controllerState) { case 0: // Initialisiert if (lastTemperature[ZULAUF] < 30) { if ((millis() - lastPumpTest) > RETRY_TIMEOUT_PUMP) { controllerState = 1; lastPumpTest = millis(); DEBUG_PRINTLN(F("Zulauf zu kalt. Schalte Pumpe für 5 Sekunden ein.")); relState[PUMPE] = true; updateRelays(); ledState[PUMPE] = relState[PUMPE]; } return; } //DEBUG_PRINTLN("x"); relState[PUMPE] = true; updateRelays(); ledState[PUMPE] = relState[PUMPE]; // nicht regulieren, wenn schon genau genug if (abs(lastTemperature[VORLAUF] - targetTemp) <= 1) { // DEBUG_PRINTLN("diff zu klein, keine Steuerung notwendig"); return; } if ((millis() - lastRegulation) > REGULATION_TIMEOUT_PUMP) { controllerState = 2; lastRegulation = millis(); int diffZualaufRuecklauf = lastTemperature[ZULAUF] - lastTemperature[RUECKLAUF]; float actPercent = (float)(lastTemperature[VORLAUF] - lastTemperature[RUECKLAUF]) * 100.0 / (float)diffZualaufRuecklauf; float shoulPercent = (float)(targetTemp - lastTemperature[RUECKLAUF]) * 100.0 / (float)diffZualaufRuecklauf; // 120 Sekunden für ganzen Weg moveSeconds = (float)MISCHER_RESET_TIME / 1000.0 / 100.0 * abs(shoulPercent - actPercent); DEBUG_PRINT(F("Berechnete Sekunden fuer Mischerumstellung ")); DEBUG_PRINTLN(moveSeconds); if (moveSeconds > 8) moveSeconds = 8; if (targetTemp > lastTemperature[VORLAUF]) { DEBUG_PRINTLN(F("Mischer auf")); relState[MISCHER_ZU] = false; relState[MISCHER_AUF] = true; updateRelays(); ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; } else { DEBUG_PRINTLN(F("Mischer zu")); relState[MISCHER_ZU] = true; relState[MISCHER_AUF] = false; updateRelays(); ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; } return; } return; break; case 1: // in Testmodus bei zu wenig Temp im Zulauf if ((millis() - lastPumpTest) > PROBE_TIMEOUT_PUMP) { relState[PUMPE] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; DEBUG_PRINTLN(F("Pumpe ausgeschaltet")); controllerState = 0; lastPumpTest = millis(); } return; break; case 2: // in der Regelung if ((millis() - lastRegulation) > moveSeconds * 1000.0) { DEBUG_PRINTLN("Mischer zu."); relState[MISCHER_ZU] = false; relState[MISCHER_AUF] = false; updateRelays(); ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; lastRegulation = millis(); controllerState = 0; } return; break; default: DEBUG_PRINT(F("ERROR, unknown state :")); DEBUG_PRINTLN(controllerState); controllerState = 0; return; } } // function to print a device address void printAddress(DeviceAddress deviceAddress) { for (uint8_t i = 0; i < 8; i++) { if (deviceAddress[i] < 16) DEBUG_PRINT("0"); #ifdef EN_DEBUG Serial.print(deviceAddress[i], HEX); #endif } } void updateRelays() { static boolean relayStateReported[8] = { false, false, false, false, false, false, false, false }; #ifndef NO_MYS static unsigned long previousStateMillis[NUMBER_OF_RELAYS] = { 0, 0, 0, 0 }; #endif for (int i = 0; i < NUMBER_OF_RELAYS; i++) { if (relState[i]) { digitalWrite(RELAY_1 + i, RELAY_ON); } else { digitalWrite(RELAY_1 + i, RELAY_OFF); } #ifndef NO_MYS bool bSend = false; if (previousStateMillis[i] == 0) { // noch nie gesendet bSend = true; } else if (relayStateReported[i] != relState[i] ) { // Änderungen melden bSend = true; } else if ((millis() - previousStateMillis[i]) > MIN_REPORT_INTERVAL) { bSend = true; } if (bSend) { // TODO: Check if we want to look at the return value of send send(msgStatus.setSensor(i + MAX_ATTACHED_DS18B20).set(relState[i] ? 1 : 0)); previousStateMillis[i] = millis(); relayStateReported[i] = relState[i]; } #endif } } void updateDisp() { static char s[8]; static unsigned long previousDisplayMillis = 0; // update display? if ((millis() - previousDisplayMillis) > 1000) { previousDisplayMillis = millis(); displayInfo++; #ifdef NO_MYS if (displayInfo > 4) displayInfo = 0; #else if (displayInfo > 5) displayInfo = 0; #endif ledModule.clearDisplay(); // sind die Temperaturen schon gelesen worden? Wenn nicht, abbrechen. if (lastTemperature[0] == -100) return; for (byte i = 0; i <= 7; i++) { if (ledState[i]) ledModule.setLED(1, i); else ledModule.setLED(0, i); } // 0 Vorlauf, 1 Rücklauf, 2 Zulauf, 3 Sollwert switch (displayInfo) { case 0: // Vorlauf sprintf(s, "Vor %2i", lastTemperature[VORLAUF]); break; case 1: // Rücklauf sprintf(s, "Rue %2i", lastTemperature[RUECKLAUF]); break; case 2: // Zulauf sprintf(s, "Zu %2i", lastTemperature[ZULAUF]); break; case 3: // Zielwert sprintf(s, "Soll %2i", targetTemp); break; case 4: // Power if (powerOn) { sprintf(s, "PowerOn"); } else { sprintf(s, "PowerOff"); } break; #ifndef NO_MYS case 5: //clock TimeChangeRule *tcr; time_t utc = millis(); time_t t = CE.toLocal(utc, &tcr); unsigned long dispTime = hour(t) * 100 * 100 + minute(t) * 100 + second(t); if (hour(t) < 10) { sprintf(s, "U 0%lu", dispTime); } else { sprintf(s, "U %lu", dispTime); } break; #endif } ledModule.setDisplayToString(s); } } void closeMischer() { relState[PUMPE] = false; relState[MISCHER_ZU] = true; relState[MISCHER_AUF] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; } #ifndef NO_MYS void before() { } // 0 Vorlauf, 1 Rücklauf, 2 Zulauf void presentation() { // Send the sketch version information to the gateway and Controller sendSketchInfo("Mischer Node", "1.1"); // Fetch the number of attached temperature sensors numSensors = sensors.getDeviceCount(); DEBUG_PRINT(F("Numsensors ")); DEBUG_PRINTLN(numSensors); // Present all sensors to controller for (int i = 0; i < numSensors && i < MAX_ATTACHED_DS18B20; i++) { present(i, S_TEMP); } for (int sensor = MAX_ATTACHED_DS18B20, pin = RELAY_1; sensor < (MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS); sensor++, pin++) { // Register all sensors to gw (they will be created as child devices) present(sensor, S_BINARY); } // Thermopunkt present(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS, S_HVAC); // Power present(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 1, S_HEATER); #ifndef NO_AC_DETECT // AC Buderuus present(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 2, S_BINATY); #endif // Power present(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 3, S_INFO); // Initialltemperatur mitteilen send(msgTargetTemp.set(targetTemp)); send(msgPower.set(powerOn)); } void receive(const MyMessage & message) { DEBUG_PRINT(F("Meldung an Sensor ")); DEBUG_PRINT(message.sensor); DEBUG_PRINT(F(" mit type ")); DEBUG_PRINTLN(message.type); if (message.type == V_STATUS) { int i = message.sensor - MAX_ATTACHED_DS18B20; if ((i >= 0) && (i < NUMBER_OF_RELAYS)) { DEBUG_PRINT(F("Schaltbefehl für Relay ")); DEBUG_PRINT(i); DEBUG_PRINT(F(" auf ")); DEBUG_PRINTLN(message.getBool()); relState[i] = message.getBool(); ledState[i] = relState[i]; } else if (i == MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 1) { powerOn = message.getBool(); send(msgPower.set(powerOn)); if (powerOn) EEPROM.write(EEPROM_POWERSTATE, 1); else EEPROM.write(EEPROM_POWERSTATE, 0); if (powerOn == false) { relState[PUMPE] = false; ledState[POWERLED] = false; DEBUG_PRINTLN(F("Befehl für PowerOff")); } else { ledState[POWERLED] = true; DEBUG_PRINTLN(F("Befehl für PowerOn")); } } updateRelays(); } else if (message.type == V_HVAC_SETPOINT_HEAT) { if (message.sensor == (MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS)) { targetTemp = message.getInt(); DEBUG_PRINT(F("Zieltemp gesetzt auf ")); DEBUG_PRINTLN(targetTemp); if (targetTemp > MAX_TEMP) targetTemp = START_TARGET_TEMP; if (targetTemp < 20) targetTemp = 20; send(msgTargetTemp.set(targetTemp)); } } } // This is called when a new time value was received void receiveTime(unsigned long controllerTime) { // Ok, set incoming time DEBUG_PRINT(F("Time value received: ")); DEBUG_PRINTLN(controllerTime); #ifndef NO_RTC RTC.set(controllerTime); else setTime(controllerTime); #endif timeReceived = true; } void sendTemp() { static int lastSentTemperature[MAX_ATTACHED_DS18B20] = { -100, -100, -100 }; static unsigned long previousTempMillis[MAX_ATTACHED_DS18B20] = { 0, 0, 0 }; for (int i = 0; i < MAX_ATTACHED_DS18B20 ; i++) { if (lastTemperature[i] != -100) { bool bSend = false; if (previousTempMillis[i] == 0) { // noch nie gesendet bSend = true; } else if (abs(lastSentTemperature[i] - lastTemperature[i]) >= 2) { // Differenz von >= zwei Grad werden gemeldet bSend = true; } else if ((millis() - previousTempMillis[i]) > MIN_REPORT_INTERVAL) { bSend = true; } if (bSend) { // TODO: Check if we want to look at the return value of send send(msgTemp.setSensor(i).set(lastTemperature[i], 1)); previousTempMillis[i] = millis(); lastSentTemperature[i] = lastTemperature[i]; } } } } #endif #ifndef NO_AC_DETECT void buderusSet() { testStateBuderus = true; } #endif void reboot() { wdt_enable(WDTO_30MS); while (1) {}; } void readButtons() { byte buttons = ledModule.getButtons(); if (lastButtonState != buttons) { lastButtonState = buttons; if (buttons > 0) { for (byte i = 0; i <= 7; i++) { if ((buttons >> i) & 1) { ledState[i] = !ledState[i]; if (i < NUMBER_OF_RELAYS) relState[i] = ledState[i]; updateRelays(); if (ledState[i]) ledModule.setLED(1, i); else ledModule.setLED(0, i); if (i == POWERLED) { powerOn = ledState[i]; #ifndef NO_MYS send(msgPower.set(powerOn)); #endif if (powerOn) EEPROM.write(EEPROM_POWERSTATE, 1); else EEPROM.write(EEPROM_POWERSTATE, 0); } if (i == TEMPDOWNLED) { targetTemp--; if (targetTemp < 30) targetTemp = 30; EEPROM.write(EEPROM_TARGET_TEMP, targetTemp); } if (i == TEMPUPLED) { targetTemp++; if (targetTemp > MAX_TEMP) targetTemp = MAX_TEMP; EEPROM.write(EEPROM_TARGET_TEMP, targetTemp); } DEBUG_PRINT(F("ButtonState changed ")); DEBUG_PRINTLN(i); } } } } } void readTemp() { static float temp; static int tempi; static unsigned long lastReadTemp1 = -1; static unsigned long lastReadTemp2 = -1; static unsigned long lastReadTemp3 = -1; if (previousTempMillis == -1) { // Dallas sensors.requestTemperatures(); previousTempMillis = nowms; } if ((millis() - previousTempMillis) >= conversionTime) { temp = sensors.getTempC(Probe01); if (temp != DEVICE_DISCONNECTED_C) { tempi = (int)(temp + 0.5); lastTemperature[VORLAUF] = tempi; lastReadTemp1 = nowms; } if (temp != DEVICE_DISCONNECTED_C) { temp = sensors.getTempC(Probe02); tempi = (int)(temp + 0.5); lastTemperature[RUECKLAUF] = tempi; lastReadTemp2 = nowms; } if (temp != DEVICE_DISCONNECTED_C) { temp = sensors.getTempC(Probe03); tempi = (int)(temp + 0.5); lastTemperature[ZULAUF] = tempi; lastReadTemp3 = nowms; } if (nowms > 60000) { // ersta nach einer minute prüfen unsigned long compare = nowms - 60000; // vor 1 Minute if ((lastReadTemp1 < compare) || (lastReadTemp2 < compare) || (lastReadTemp3 < compare)) { DEBUG_PRINTLN(F("Zu lange keine Temeratur -> reset")); lastReadTemp1 = -1; lastReadTemp2 = -1; lastReadTemp3 = -1; ledModule.setDisplayToString(F("ERR Reb")); delay(1000); reboot(); } } previousTempMillis = -1; } #ifdef SIMULATE_VOR lastTemperature[VORLAUF] = SIMULATE_VOR; lastReadTemp1 = nowms; #endif #ifdef SIMULATE_RUE lastTemperature[RUECKLAUF] = SIMULATE_RUE; lastReadTemp3 = nowms; #endif #ifdef SIMULATE_ZU lastTemperature[ZULAUF] = SIMULATE_ZU; lastReadTemp3 = nowms; #endif } #ifndef NO_AC_DETECT void readAC() { if ((millis() - lastResetBuderus) > 100) // bei 50 HZ sind das 25 Durchgänge... { noInterrupts(); if (testStateBuderus != powerOnBuderus ) { powerOnBuderus = testStateBuderus; testStateBuderus = false; interrupts(); ledState[BUDERUSLED] = powerOnBuderus; #ifndef NO_MYS send(msgPowerBuderus.set(powerOnBuderus)); #endif } lastResetBuderus = nowms; testStateBuderus = false; } else interrupts(); } #endif -
I had a similar problem with the control of a heating mixer and three dallas sensors. I solved the problem with:
- replacement of the relays with solid state relays
- moved conttroller more in distance of the high voltage parts
I also added a watchdog and a reboot mechanism in case of sensor problems.
Maybe this sketch can give you an inspiration: (work in progress, MYS-Part not tested in depth)
// Enable debug prints to serial monitor //#define MY_DEBUG // in Mysensors #define EN_DEBUG // in this sketch //#define NO_MYS // ohne Mysensors Unterstützung? //#define SIMULATION #define NO_AC_DETECT // ohne AC sensor #define NO_RTC // RTC nur zusammen mit Mysensors #ifdef NO_MYS #ifndef NO_RTC #define NO_RTC #endif #endif #ifdef SIMULATION // für Simulation ohne Sensoren #define SIMULATE_VOR 35 #define SIMULATE_RUE 30 #define SIMULATE_ZU 65 #ifdef SIMULATE_VOR #warning Achtung! Keine Echtentemperaturmessungen -> Simulation #endif #ifdef SIMULATE_RUE #warning Achtung! Keine Echtentemperaturmessungen -> Simulation #endif #ifdef SIMULATE_ZU #warning Achtung! Keine Echtentemperaturmessungen -> Simulation #endif #endif #define START_TARGET_TEMP 40 #define EEPROM_TARGET_TEMP 900 // Save Porisiton. It is above the Mysensors range of lib 2.1 #define EEPROM_POWERSTATE 902 // Save Porisiton. It is above the Mysensors range of lib 2.1 #define MAX_TEMP 50 #define VORLAUF 0 #define RUECKLAUF 1 #define ZULAUF 2 #define PUMPE 0 #define MISCHER_ZU 1 #define MISCHER_AUF 2 #define POWERLED 7 // 8. LED #define TEMPDOWNLED 5 // 6. Led #define TEMPUPLED 6 // 7. Led #ifndef NO_AC_DETECT #define BUDERUSLED 4 // 5. Led #endif #define RETRY_TIMEOUT_PUMP 2*60*1000UL // alle 2 Minuten testen, ob Vorlauf nicht besser (5 Sekunden pumpen) #define REGULATION_TIMEOUT_PUMP 30*1000UL // 30 Sekunden warten nach neuer Einstellung #define PROBE_TIMEOUT_PUMP 5*1000UL // 5 Sekunden Pumpe für Test einschalten, wenn Zulauf zu kalt #define BUDERUS_PIN 3 // Buderus Powererkennung Pumpe auf PIN 3 #ifndef SIMULATION #define MISCHER_RESET_TIME 120*1000UL // 2 Minuten bis Nullstellung #else #define MISCHER_RESET_TIME 10*1000UL // 10 Sekunden bis Nullstellung nei Simulation #endif #ifdef EN_DEBUG #define DEBUG_PRINT(x) Serial.print (x) #else #define DEBUG_PRINT(x) #endif #ifdef EN_DEBUG #define DEBUG_PRINTLN(x) Serial.println (x) #else #define DEBUG_PRINTLN(x) #endif #ifndef NO_MYS // Radio Configuration #define MY_TRANSPORT_WAIT_READY_MS (10000ul) #define MY_RADIO_RFM69 #define MY_RFM69_FREQUENCY RF69_868MHZ #define MY_RFM69_NETWORKID 13 #define MY_RFM69_ENABLE_ENCRYPTION #define MY_NODE_ID 168 //#define MY_IS_RFM69HW #endif #include <Arduino.h> #include <avr/wdt.h> #include <EEPROM.h> #include <MemoryFree.h> #ifndef NO_MYS #define MIN_REPORT_INTERVAL 5 * 60 * 1000L // mindestens alle 5 Minuten melden #include <SPI.h> #include <MySensors.h> #include <Time.h> //http://www.arduino.cc/playground/Code/Time #include <Timezone.h> //https://github.com/JChristensen/Timezone #include <TimeLib.h> //Central European Time (Frankfurt, Paris) TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; //Central European Standard Time Timezone CE(CEST, CET); bool timeReceived = false; unsigned long lastUpdate = 0, lastRequest = 0; #endif #ifndef NO_RTC #include <DS3232RTC.h> // A DS3231/DS3232 library #endif #define MAX_LEDS 8 byte lastButtonState = 0; #define RELAY_ON HIGH #define RELAY_OFF LOW #define RELAY_1 A0 // Arduino Digital I/O pin number for first relay (second on pin+1 etc) #define NUMBER_OF_RELAYS 4 // Total number of attached relays boolean ledState[MAX_LEDS] = { false, false, false, false, false, false, false, false }; boolean relState[NUMBER_OF_RELAYS] = { false, false, false, false }; #include <TM1638.h> #include <DallasTemperature.h> #include <OneWire.h> #define ONE_WIRE_BUS 6 // Pin where dallase sensor is connected #define TEMPERATURE_PRECISION 9 #define MAX_ATTACHED_DS18B20 3 //28B404080000804A DeviceAddress Probe01 = { 0x28, 0xB4, 0x04, 0x08, 0x00, 0x00, 0x80, 0x4A }; //28C606080000803F DeviceAddress Probe02 = { 0x28, 0xC6, 0x06, 0x08, 0x00, 0x00, 0x80, 0x3F }; //28750808000080C3 DeviceAddress Probe03 = { 0x28, 0x75, 0x08, 0x08, 0x00, 0x00, 0x80, 0xC3 }; 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. int numSensors = 0; int lastTemperature[MAX_ATTACHED_DS18B20] = { -100, -100, -100 }; int16_t conversionTime; unsigned long previousTempMillis = -1; static unsigned long nowms = millis(); // update at start of loop() // define LCD module TM1638 ledModule(8, 9, 7); int displayInfo = -1; unsigned long previousDisplayMillis = 0; int targetTemp = START_TARGET_TEMP; #ifdef SIMULATION bool powerOn = true; #ifndef NO_AC_DETECT bool powerOnBuderus = true; #endif #else bool powerOn = false; #ifndef NO_AC_DETECT bool powerOnBuderus = false; #endif #endif bool resetMischer = true; // mischer zuerst in Nullstellung #ifndef NO_AC_DETECT bool testStateBuderus = false; unsigned long lastResetBuderus = -1; #endif #ifndef NO_MYS // Initialize messages MyMessage msgTemp(0, V_TEMP); MyMessage msgStatus(0, V_STATUS); MyMessage msgTargetTemp(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS, V_HVAC_SETPOINT_HEAT); MyMessage msgPower(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 1, V_STATUS); #ifndef NO_AC_DETECT MyMessage msgPowerBuderus(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 2, V_STATUS); #endif MyMessage msgDebug(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 3, V_TEXT); #endif // the setup function runs once when you press reset or power the board void setup() { DEBUG_PRINTLN(F("Starte setup")); wdt_enable(WDTO_8S); Serial.begin(115200); #ifndef NO_RTC // the function to get the time from the RTC setSyncProvider(RTC.get); #endif #ifndef NO_MYS // Request latest time from controller at startup requestTime(); #endif // Zieltemperatur aus EERPOM lesem: targetTemp = EEPROM.read(EEPROM_TARGET_TEMP); if ((targetTemp < 30) || (targetTemp > MAX_TEMP)) { targetTemp = START_TARGET_TEMP; EEPROM.write(EEPROM_TARGET_TEMP, targetTemp); } int state = EEPROM.read(EEPROM_POWERSTATE); if (state == 0) { powerOn = false; } else powerOn = true; #ifndef NO_AC_DETECT // Buderuserkennung auf PIN3 attachInterrupt(digitalPinToInterrupt(BUDERUS_PIN), buderusSet, CHANGE); testStateBuderus = false; lastResetBuderus = millis(); #ifndef NO_MYS send(msgPowerBuderus.set(powerOnBuderus)); #endif #endif // Relayausgänge initialisiern 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, RELAY_OFF); } // Dallas Temperatursensoren sensors.begin(); sensors.setWaitForConversion(false); numSensors = sensors.getDeviceCount(); DEBUG_PRINT(F("Dallas Sensoren ")); DEBUG_PRINTLN(numSensors); DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address for (int i = 0; i < numSensors; i++) { wdt_reset(); // Search the wire for address if (sensors.getAddress(tempDeviceAddress, i)) { DEBUG_PRINT(F("Found device ")); #ifdef EN_DEBUG Serial.print(i, DEC); #endif DEBUG_PRINT(F(" with address: ")); printAddress(tempDeviceAddress); DEBUG_PRINTLN(); DEBUG_PRINT(F("Setting resolution to ")); #ifdef EN_DEBUG Serial.println(TEMPERATURE_PRECISION, DEC); #endif // set the resolution to 12 bit (Each Dallas/Maxim device is capable of several different resolutions) sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION); DEBUG_PRINT(F("Resolution actually set to: ")); #ifdef EN_DEBUG Serial.print(sensors.getResolution(tempDeviceAddress), DEC); #endif DEBUG_PRINTLN(); } else { DEBUG_PRINT(F("Found ghost device at ")); #ifdef EN_DEBUG Serial.print(i, DEC); #endif DEBUG_PRINT(F(" but could not detect address. Check power and cabling")); } } wdt_reset(); sensors.requestTemperatures(); // query conversion time and sleep until conversion completed conversionTime = sensors.millisToWaitForConversion(sensors.getResolution()); } /*****************************************************/ // the loop function runs over and over again forever void loop() { nowms = millis(); #ifndef NO_MYS // If no time has been received yet, request it every 10 second from controller // When time has been received, request update every hour if ((!timeReceived && (nowms - lastRequest) > (10UL * 1000UL)) || (timeReceived && (nowms - lastRequest) > (60UL * 1000UL * 60UL))) { // Request time from controller. DEBUG_PRINTLN("requesting time"); requestTime(); lastRequest = nowms; } #endif wdt_reset(); #ifndef NO_AC_DETECT readAC(); #endif readTemp(); readButtons(); updateDisp(); // Temperaturen senden #ifndef NO_MYS sendTemp(); #endif // Kontroller control(); // Loop 2x pro Sekunde ist aureichend unsigned long loopTime = millis() - nowms; if (loopTime < 450) { #ifdef NO_MYS delay (500 - loopTime); #else wait (500 - loopTime); #endif } } // end loop /**************************************************************/ // Steuerung void control() { wdt_reset(); static unsigned long lastPumpTest = 0; static unsigned long lastRegulation = -REGULATION_TIMEOUT_PUMP; static unsigned long resetStart = 0; // wann wurde die Rücksetzung des Mischers gestartet static bool lastPower = powerOn; static float moveSeconds = 0.0; // Zeiten für Stellmotor Mischer // controllerState // 0 initialized // 1 Pumpe für kurzen test aktiviert, warten auf Timeout für Deaktivierung // 2 in der Regelung, warten auf Timeout für Deaktivierung // 3 in Ausganglage fahren static int controllerState = 0; // Emergency if (lastTemperature[VORLAUF] > MAX_TEMP) { if (resetStart == 0) { if (relState[PUMPE]) { DEBUG_PRINT(F("Zu heiss. Emergency Mischer schliessen")); DEBUG_PRINTLN(lastTemperature[VORLAUF]); } closeMischer(); controllerState = 0; return; } } // Temperatur noch nicht gelesen; if (lastTemperature[VORLAUF] == -100) return; // Fehler mit den Sensoren if ((lastTemperature[VORLAUF] < 0) || (lastTemperature[VORLAUF] > 100) || (lastTemperature[RUECKLAUF] < 0) || (lastTemperature[RUECKLAUF] > 100) || (lastTemperature[ZULAUF] < 0) || (lastTemperature[ZULAUF] > 100)) { relState[PUMPE] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; // Test //powerOn = false; #ifndef NO_MYS //send(msgPower.set(powerOn)); #endif controllerState = 0; DEBUG_PRINTLN(F("Fehler mit den Sensoren, Temperaturen unter 0 oder über 100. Poweroff!")); return; } if (resetMischer) { DEBUG_PRINTLN(F("Mischer initialisieren")); closeMischer(); resetStart = millis(); resetMischer = false; controllerState = 0; return; } if (resetStart > 0) { if ((millis() - resetStart) > MISCHER_RESET_TIME) { DEBUG_PRINTLN(F("Mischer fertig initialisiert")); relState[MISCHER_ZU] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; ledState[MISCHER_ZU] = relState[MISCHER_ZU]; resetStart = 0; controllerState = 0; } return; } // wenn ausser Betrieb -> verlassen; if (powerOn == false) { if (lastPower == false) return; DEBUG_PRINTLN("Go to power off state"); #ifndef NO_MYS send(msgPower.set(powerOn)); #endif lastPower = false; relState[PUMPE] = false; relState[MISCHER_ZU] = false; relState[MISCHER_AUF] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; controllerState = 0; EEPROM.write(EEPROM_POWERSTATE, 0); return; } //DEBUG_PRINTLN("a"); lastPower = true; switch (controllerState) { case 0: // Initialisiert if (lastTemperature[ZULAUF] < 30) { if ((millis() - lastPumpTest) > RETRY_TIMEOUT_PUMP) { controllerState = 1; lastPumpTest = millis(); DEBUG_PRINTLN(F("Zulauf zu kalt. Schalte Pumpe für 5 Sekunden ein.")); relState[PUMPE] = true; updateRelays(); ledState[PUMPE] = relState[PUMPE]; } return; } //DEBUG_PRINTLN("x"); relState[PUMPE] = true; updateRelays(); ledState[PUMPE] = relState[PUMPE]; // nicht regulieren, wenn schon genau genug if (abs(lastTemperature[VORLAUF] - targetTemp) <= 1) { // DEBUG_PRINTLN("diff zu klein, keine Steuerung notwendig"); return; } if ((millis() - lastRegulation) > REGULATION_TIMEOUT_PUMP) { controllerState = 2; lastRegulation = millis(); int diffZualaufRuecklauf = lastTemperature[ZULAUF] - lastTemperature[RUECKLAUF]; float actPercent = (float)(lastTemperature[VORLAUF] - lastTemperature[RUECKLAUF]) * 100.0 / (float)diffZualaufRuecklauf; float shoulPercent = (float)(targetTemp - lastTemperature[RUECKLAUF]) * 100.0 / (float)diffZualaufRuecklauf; // 120 Sekunden für ganzen Weg moveSeconds = (float)MISCHER_RESET_TIME / 1000.0 / 100.0 * abs(shoulPercent - actPercent); DEBUG_PRINT(F("Berechnete Sekunden fuer Mischerumstellung ")); DEBUG_PRINTLN(moveSeconds); if (moveSeconds > 8) moveSeconds = 8; if (targetTemp > lastTemperature[VORLAUF]) { DEBUG_PRINTLN(F("Mischer auf")); relState[MISCHER_ZU] = false; relState[MISCHER_AUF] = true; updateRelays(); ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; } else { DEBUG_PRINTLN(F("Mischer zu")); relState[MISCHER_ZU] = true; relState[MISCHER_AUF] = false; updateRelays(); ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; } return; } return; break; case 1: // in Testmodus bei zu wenig Temp im Zulauf if ((millis() - lastPumpTest) > PROBE_TIMEOUT_PUMP) { relState[PUMPE] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; DEBUG_PRINTLN(F("Pumpe ausgeschaltet")); controllerState = 0; lastPumpTest = millis(); } return; break; case 2: // in der Regelung if ((millis() - lastRegulation) > moveSeconds * 1000.0) { DEBUG_PRINTLN("Mischer zu."); relState[MISCHER_ZU] = false; relState[MISCHER_AUF] = false; updateRelays(); ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; lastRegulation = millis(); controllerState = 0; } return; break; default: DEBUG_PRINT(F("ERROR, unknown state :")); DEBUG_PRINTLN(controllerState); controllerState = 0; return; } } // function to print a device address void printAddress(DeviceAddress deviceAddress) { for (uint8_t i = 0; i < 8; i++) { if (deviceAddress[i] < 16) DEBUG_PRINT("0"); #ifdef EN_DEBUG Serial.print(deviceAddress[i], HEX); #endif } } void updateRelays() { static boolean relayStateReported[8] = { false, false, false, false, false, false, false, false }; #ifndef NO_MYS static unsigned long previousStateMillis[NUMBER_OF_RELAYS] = { 0, 0, 0, 0 }; #endif for (int i = 0; i < NUMBER_OF_RELAYS; i++) { if (relState[i]) { digitalWrite(RELAY_1 + i, RELAY_ON); } else { digitalWrite(RELAY_1 + i, RELAY_OFF); } #ifndef NO_MYS bool bSend = false; if (previousStateMillis[i] == 0) { // noch nie gesendet bSend = true; } else if (relayStateReported[i] != relState[i] ) { // Änderungen melden bSend = true; } else if ((millis() - previousStateMillis[i]) > MIN_REPORT_INTERVAL) { bSend = true; } if (bSend) { // TODO: Check if we want to look at the return value of send send(msgStatus.setSensor(i + MAX_ATTACHED_DS18B20).set(relState[i] ? 1 : 0)); previousStateMillis[i] = millis(); relayStateReported[i] = relState[i]; } #endif } } void updateDisp() { static char s[8]; static unsigned long previousDisplayMillis = 0; // update display? if ((millis() - previousDisplayMillis) > 1000) { previousDisplayMillis = millis(); displayInfo++; #ifdef NO_MYS if (displayInfo > 4) displayInfo = 0; #else if (displayInfo > 5) displayInfo = 0; #endif ledModule.clearDisplay(); // sind die Temperaturen schon gelesen worden? Wenn nicht, abbrechen. if (lastTemperature[0] == -100) return; for (byte i = 0; i <= 7; i++) { if (ledState[i]) ledModule.setLED(1, i); else ledModule.setLED(0, i); } // 0 Vorlauf, 1 Rücklauf, 2 Zulauf, 3 Sollwert switch (displayInfo) { case 0: // Vorlauf sprintf(s, "Vor %2i", lastTemperature[VORLAUF]); break; case 1: // Rücklauf sprintf(s, "Rue %2i", lastTemperature[RUECKLAUF]); break; case 2: // Zulauf sprintf(s, "Zu %2i", lastTemperature[ZULAUF]); break; case 3: // Zielwert sprintf(s, "Soll %2i", targetTemp); break; case 4: // Power if (powerOn) { sprintf(s, "PowerOn"); } else { sprintf(s, "PowerOff"); } break; #ifndef NO_MYS case 5: //clock TimeChangeRule *tcr; time_t utc = millis(); time_t t = CE.toLocal(utc, &tcr); unsigned long dispTime = hour(t) * 100 * 100 + minute(t) * 100 + second(t); if (hour(t) < 10) { sprintf(s, "U 0%lu", dispTime); } else { sprintf(s, "U %lu", dispTime); } break; #endif } ledModule.setDisplayToString(s); } } void closeMischer() { relState[PUMPE] = false; relState[MISCHER_ZU] = true; relState[MISCHER_AUF] = false; updateRelays(); ledState[PUMPE] = relState[PUMPE]; ledState[MISCHER_ZU] = relState[MISCHER_ZU]; ledState[MISCHER_AUF] = relState[MISCHER_AUF]; } #ifndef NO_MYS void before() { } // 0 Vorlauf, 1 Rücklauf, 2 Zulauf void presentation() { // Send the sketch version information to the gateway and Controller sendSketchInfo("Mischer Node", "1.1"); // Fetch the number of attached temperature sensors numSensors = sensors.getDeviceCount(); DEBUG_PRINT(F("Numsensors ")); DEBUG_PRINTLN(numSensors); // Present all sensors to controller for (int i = 0; i < numSensors && i < MAX_ATTACHED_DS18B20; i++) { present(i, S_TEMP); } for (int sensor = MAX_ATTACHED_DS18B20, pin = RELAY_1; sensor < (MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS); sensor++, pin++) { // Register all sensors to gw (they will be created as child devices) present(sensor, S_BINARY); } // Thermopunkt present(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS, S_HVAC); // Power present(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 1, S_HEATER); #ifndef NO_AC_DETECT // AC Buderuus present(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 2, S_BINATY); #endif // Power present(MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 3, S_INFO); // Initialltemperatur mitteilen send(msgTargetTemp.set(targetTemp)); send(msgPower.set(powerOn)); } void receive(const MyMessage & message) { DEBUG_PRINT(F("Meldung an Sensor ")); DEBUG_PRINT(message.sensor); DEBUG_PRINT(F(" mit type ")); DEBUG_PRINTLN(message.type); if (message.type == V_STATUS) { int i = message.sensor - MAX_ATTACHED_DS18B20; if ((i >= 0) && (i < NUMBER_OF_RELAYS)) { DEBUG_PRINT(F("Schaltbefehl für Relay ")); DEBUG_PRINT(i); DEBUG_PRINT(F(" auf ")); DEBUG_PRINTLN(message.getBool()); relState[i] = message.getBool(); ledState[i] = relState[i]; } else if (i == MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS + 1) { powerOn = message.getBool(); send(msgPower.set(powerOn)); if (powerOn) EEPROM.write(EEPROM_POWERSTATE, 1); else EEPROM.write(EEPROM_POWERSTATE, 0); if (powerOn == false) { relState[PUMPE] = false; ledState[POWERLED] = false; DEBUG_PRINTLN(F("Befehl für PowerOff")); } else { ledState[POWERLED] = true; DEBUG_PRINTLN(F("Befehl für PowerOn")); } } updateRelays(); } else if (message.type == V_HVAC_SETPOINT_HEAT) { if (message.sensor == (MAX_ATTACHED_DS18B20 + NUMBER_OF_RELAYS)) { targetTemp = message.getInt(); DEBUG_PRINT(F("Zieltemp gesetzt auf ")); DEBUG_PRINTLN(targetTemp); if (targetTemp > MAX_TEMP) targetTemp = START_TARGET_TEMP; if (targetTemp < 20) targetTemp = 20; send(msgTargetTemp.set(targetTemp)); } } } // This is called when a new time value was received void receiveTime(unsigned long controllerTime) { // Ok, set incoming time DEBUG_PRINT(F("Time value received: ")); DEBUG_PRINTLN(controllerTime); #ifndef NO_RTC RTC.set(controllerTime); else setTime(controllerTime); #endif timeReceived = true; } void sendTemp() { static int lastSentTemperature[MAX_ATTACHED_DS18B20] = { -100, -100, -100 }; static unsigned long previousTempMillis[MAX_ATTACHED_DS18B20] = { 0, 0, 0 }; for (int i = 0; i < MAX_ATTACHED_DS18B20 ; i++) { if (lastTemperature[i] != -100) { bool bSend = false; if (previousTempMillis[i] == 0) { // noch nie gesendet bSend = true; } else if (abs(lastSentTemperature[i] - lastTemperature[i]) >= 2) { // Differenz von >= zwei Grad werden gemeldet bSend = true; } else if ((millis() - previousTempMillis[i]) > MIN_REPORT_INTERVAL) { bSend = true; } if (bSend) { // TODO: Check if we want to look at the return value of send send(msgTemp.setSensor(i).set(lastTemperature[i], 1)); previousTempMillis[i] = millis(); lastSentTemperature[i] = lastTemperature[i]; } } } } #endif #ifndef NO_AC_DETECT void buderusSet() { testStateBuderus = true; } #endif void reboot() { wdt_enable(WDTO_30MS); while (1) {}; } void readButtons() { byte buttons = ledModule.getButtons(); if (lastButtonState != buttons) { lastButtonState = buttons; if (buttons > 0) { for (byte i = 0; i <= 7; i++) { if ((buttons >> i) & 1) { ledState[i] = !ledState[i]; if (i < NUMBER_OF_RELAYS) relState[i] = ledState[i]; updateRelays(); if (ledState[i]) ledModule.setLED(1, i); else ledModule.setLED(0, i); if (i == POWERLED) { powerOn = ledState[i]; #ifndef NO_MYS send(msgPower.set(powerOn)); #endif if (powerOn) EEPROM.write(EEPROM_POWERSTATE, 1); else EEPROM.write(EEPROM_POWERSTATE, 0); } if (i == TEMPDOWNLED) { targetTemp--; if (targetTemp < 30) targetTemp = 30; EEPROM.write(EEPROM_TARGET_TEMP, targetTemp); } if (i == TEMPUPLED) { targetTemp++; if (targetTemp > MAX_TEMP) targetTemp = MAX_TEMP; EEPROM.write(EEPROM_TARGET_TEMP, targetTemp); } DEBUG_PRINT(F("ButtonState changed ")); DEBUG_PRINTLN(i); } } } } } void readTemp() { static float temp; static int tempi; static unsigned long lastReadTemp1 = -1; static unsigned long lastReadTemp2 = -1; static unsigned long lastReadTemp3 = -1; if (previousTempMillis == -1) { // Dallas sensors.requestTemperatures(); previousTempMillis = nowms; } if ((millis() - previousTempMillis) >= conversionTime) { temp = sensors.getTempC(Probe01); if (temp != DEVICE_DISCONNECTED_C) { tempi = (int)(temp + 0.5); lastTemperature[VORLAUF] = tempi; lastReadTemp1 = nowms; } if (temp != DEVICE_DISCONNECTED_C) { temp = sensors.getTempC(Probe02); tempi = (int)(temp + 0.5); lastTemperature[RUECKLAUF] = tempi; lastReadTemp2 = nowms; } if (temp != DEVICE_DISCONNECTED_C) { temp = sensors.getTempC(Probe03); tempi = (int)(temp + 0.5); lastTemperature[ZULAUF] = tempi; lastReadTemp3 = nowms; } if (nowms > 60000) { // ersta nach einer minute prüfen unsigned long compare = nowms - 60000; // vor 1 Minute if ((lastReadTemp1 < compare) || (lastReadTemp2 < compare) || (lastReadTemp3 < compare)) { DEBUG_PRINTLN(F("Zu lange keine Temeratur -> reset")); lastReadTemp1 = -1; lastReadTemp2 = -1; lastReadTemp3 = -1; ledModule.setDisplayToString(F("ERR Reb")); delay(1000); reboot(); } } previousTempMillis = -1; } #ifdef SIMULATE_VOR lastTemperature[VORLAUF] = SIMULATE_VOR; lastReadTemp1 = nowms; #endif #ifdef SIMULATE_RUE lastTemperature[RUECKLAUF] = SIMULATE_RUE; lastReadTemp3 = nowms; #endif #ifdef SIMULATE_ZU lastTemperature[ZULAUF] = SIMULATE_ZU; lastReadTemp3 = nowms; #endif } #ifndef NO_AC_DETECT void readAC() { if ((millis() - lastResetBuderus) > 100) // bei 50 HZ sind das 25 Durchgänge... { noInterrupts(); if (testStateBuderus != powerOnBuderus ) { powerOnBuderus = testStateBuderus; testStateBuderus = false; interrupts(); ledState[BUDERUSLED] = powerOnBuderus; #ifndef NO_MYS send(msgPowerBuderus.set(powerOnBuderus)); #endif } lastResetBuderus = nowms; testStateBuderus = false; } else interrupts(); } #endifThat was very advanced =) I don't have any high voltage involved. Only have a test setup on a breadboard.
I tried to move the sensors.begin to the setup, but then I don't get any temperature readings?
-
It is the same sketch as my second post.
Haven't done anything with the hardware yet. Was following Fabiens advice with using 2.1 on both sketch and gateway. And restart gateway with problem. And then test again and restart node when the problem occurs.
-
You may want to check which version of the onewire library you are running. I was having exactly the same issue and fixed it by upgrading the onewire library from 2.7.2 (I think?) To the latest version.
It's been a few weeks now with no crashes.
-
You may want to check which version of the onewire library you are running. I was having exactly the same issue and fixed it by upgrading the onewire library from 2.7.2 (I think?) To the latest version.
It's been a few weeks now with no crashes.
@Darren-McInnes said:
You may want to check which version of the onewire library you are running. I was having exactly the same issue and fixed it by upgrading the onewire library from 2.7.2 (I think?) To the latest version.
It's been a few weeks now with no crashes.
In the Arduino IDE version 2.3.2 seems to be the latest. But is there a newer one that I can download and install?
Maybe should figure out why I don't get any sensor readings when I have sensors.begin() in the setup. Maybe that is a problem also that I have it in the loop()?
-
Sorry i meant the dallastemperature library!
i'm running 3.7.5 now without issues but had problems after a day with 3.7.2
my ide version is 1.6.9 and onewire version 2.3.2
-
Sorry i meant the dallastemperature library!
i'm running 3.7.5 now without issues but had problems after a day with 3.7.2
my ide version is 1.6.9 and onewire version 2.3.2
I have 3.7.6 installed. On thing might just be updated libraries. I have been using Visual Studio for development with the plugin from Visual Micro. But then the libraries don't get updated. Had some problems with a update from Visual Micro so I went back to the Arduino IDE.
Have been running since Monday now. Although it could take more than a week before any problem, but I'm keeping my fingers crossed. -
I have 3.7.6 installed. On thing might just be updated libraries. I have been using Visual Studio for development with the plugin from Visual Micro. But then the libraries don't get updated. Had some problems with a update from Visual Micro so I went back to the Arduino IDE.
Have been running since Monday now. Although it could take more than a week before any problem, but I'm keeping my fingers crossed. -
@raptorjr
I am also using visual studio but libraries and boards get updated through the arduino ide without problemsBut if you never open the Arduino IDE it can't get updated? Or are you saying that they get updated through Visual Studio?
I hadn't used the IDE for several months. Thought I was a step closer to the problem and that it was bugs in older libraries.
-
But if you never open the Arduino IDE it can't get updated? Or are you saying that they get updated through Visual Studio?
I hadn't used the IDE for several months. Thought I was a step closer to the problem and that it was bugs in older libraries.