From 5de51f34a355c2e8e1dd9ebb6c61fd64668997fa Mon Sep 17 00:00:00 2001 From: tthden Date: Sun, 10 May 2026 17:54:54 +0200 Subject: [PATCH] Implementatie alarm, bel en box, fan, temperatuur sensoren, p1 uitlezen met esp32 wrooom-32Dmodule; wifi werkt niet goed --- .../MeterKastControllerEsp32.ino | 1331 +++++++++++++++++ 1 file changed, 1331 insertions(+) create mode 100644 MeterKastControllerEsp32/MeterKastControllerEsp32.ino diff --git a/MeterKastControllerEsp32/MeterKastControllerEsp32.ino b/MeterKastControllerEsp32/MeterKastControllerEsp32.ino new file mode 100644 index 0000000..0a8ce94 --- /dev/null +++ b/MeterKastControllerEsp32/MeterKastControllerEsp32.ino @@ -0,0 +1,1331 @@ +#include "esp_wifi.h" +#include +#include +#include +#include +#include "Adafruit_DS248x.h" +//Je kunt de fout in de bibliotheek zelf simpel corrigeren. +//De compiler geeft je eigenlijk al de oplossing in de foutmelding: +//Open het bestand: C:\Users\tthde\Documents\Arduino\libraries\ESPAsyncWebServer\src\WebAuthentication.cpp +//Zoek naar de regels 74, 75 en 76. +//Verwijder de toevoeging _ret van de drie functienamen. +//Verander mbedtls_md5_starts_ret naar mbedtls_md5_startsVerander mbedtls_md5_update_ret naar mbedtls_md5_updateVerander mbedtls_md5_finish_ret naar mbedtls_md5_finish + + +#define DS18B20_FAMILY_CODE 0x28 +#define DS18B20_CMD_CONVERT_T 0x44 +#define DS18B20_CMD_MATCH_ROM 0x55 +#define DS18B20_CMD_READ_SCRATCHPAD 0xBE + +#define temp_addr_read 0x4F //DS1721 +#define temp_addr_write 0x4F //DS1721 + +// --- NETWERK CONFIGURATIE --- +const char* ssid = "CAM_LINK"; +const char* password = "DENWEP128BITSDEN46WIRELESSVIGOR"; + +const char* mqtt_server = "192.168.200.26"; +const int mqttPort = 1883; +const char* mqttUser = "vlc_viewer"; +const char* mqttPassword = "vlc_viewer12"; +const char* mqttClientId = "MeterKastController"; + +const char* mqttTopicBelVoorTest = "BelVoorTest"; +const char* mqttTopicRestarCamera = "RestartCamera"; +const char* mqttTopicDisableVAlarm = "DisableVAlarm"; +const char* mqttTopicEnableVAlarm = "EnableVAlarm"; +const char* mqttTopicActivateFan = "ActivateFanMeterkast"; +const char* mqttTopicDeactivateFan = "DeactivateFanMeterkast"; +const char* mqttTopicActivateBuzzer = "ActivateAlarmBuzzer"; +const char* mqttTopicDeactivateBuzzer = "DeactivateAlarmBuzzer"; +const char* mqttTopicAlarmLampAan = "AlarmLampAan"; +const char* mqttTopicAlarmLampUit = "AlarmLAmpUit"; + +const char* mqttTopicDalVerbruikt = "DalVerbruikt_kwh"; +const char* mqttTopicPiekVerbruikt = "PiekVerbruikt_kwh"; +const char* mqttTopicDalGeleverd = "DalGeleverd_kwh"; +const char* mqttTopicPiekGeleverd = "PiekGeleverd_kwh"; +const char* mqttTopicHuidigVerbruik = "HuidigVerbruik_kw"; +const char* mqttTopicHuidigGeleverd = "HuidigGeleverd_kw"; +const char* mqttTopicGasTotaal = "gas_totaal_m3"; + +const char* mqttTopicTempMeterKast = "TempMeterKast"; +const char* mqttTopicTempThermostaat = "TempThermostaat"; +const char* mqttTopicTempBuiten = "TempBuiten"; +const char* mqttTopicTempKamer = "TempKamer"; +const char* mqttTopicTempOverloop = "TempOverloop"; +const char* mqttTopicTempMeterKastController = "TempMeterKastController"; + +const char* mqttTopicHcProtected = "HcProtected"; +const char* mqttTopicHcAlarm = "HcAlarm"; +const char* mqttTopicHcVAlarm = "HcVAlarm"; +const char* mqttTopicHcAlarmBuzzer = "HcAlarmBuzzer"; +const char* mqttTopicHcAlarmLamp = "HCLampAlarm"; +const char* mqttTopicFanMeterkast = "FanMeterKast"; +const char* mqttTopicAlarmStatus = "AlarmStatus"; +const char* mqttTopicP1Line = "P1Line"; +const char* mqttTopicP1InvalidLine = "P1InvalidLine"; +const char* mqttTopicSerialOutput = "SerialOutput"; + +const char* mqtt_temperature_topic = "BrievenbusTemperatuur"; +const char* mqtt_bel_topic = "BelVoor"; +const char* mqtt_bel_state_topic = "BelVoorStatus"; +const char* mqtt_test_topic = "BrievenbusTest"; +const char* mqtt_debug_topic = "BrievenbusDebug"; +const char* mqtt_box_state_topic = "BrievenbusStatus"; +const char* mqtt_box_opened_topic = "BrievenbusOpen"; +const char* mqtt_box_closed_topic = "BrievenbusDicht"; +const char* mqtt_info_topic = "BrievenbusInfo"; +char result[50]; +unsigned long lastTimeHost = 0; +int result_length; + + +// --- PIN DEFINITIES --- +const int PIN_SDA = 21; +const int PIN_SCL = 22; +const int PIN_BUZZER = 32; +const int PIN_VALARM = 27; +const int PIN_FAN = 33; +const int PIN_ALARMLAMP = 18; +const int PIN_RELAIS_BEL = 19; +const int PIN_INPUT_DOOR = 15; // T1_DOOR: DoorsOpen DR +const int PIN_INPUT_ACT = 13; // T2_ACT: AlarmActivated (Extern signaal) SL +const int PIN_RELAIS_CAM = 23; +const int PIN_P1_REQ = 17; +const int PIN_WATER_SENSOR = 25; +const int PIN_BEL = 12; +const int PIN_BOX = 14; + +volatile byte interruptCounterBel = 0; +volatile byte interruptCounterBox = 0; + + +void IRAM_ATTR handleInterruptbel() { + interruptCounterBel++; +} + +void IRAM_ATTR handleInterruptbox() { + interruptCounterBox++; +} +int numberOfInterruptsBel = 0; +int numberOfInterruptsBox = 0; +// the following variables are unsigned longs because the time, measured in +// milliseconds, will quickly become a bigger number than can be stored in an int. +unsigned long lastDebounceTimeBel = 0; // the last time the bel knob was handled +unsigned long lastDebounceTimeBox = 0; // the last time the bel knob was handled +#define debounceDelayBel 1000 // the debounce time; +#define debounceDelayBox 1000 // the debounce time; +float temperature; +unsigned long temp_readoutTime = 0; +int boxState = 0; +unsigned long box_readoutTime = 0; +unsigned long bel_readoutTime = 0; +int belState = 0; +int prev_boxState = -1; +int prev_belState = -1; + +unsigned long info_Time = 0; + + + +bool wifiRestarted = false; +bool wifiNeedsRestart = false; + + +// --- ALARM STATES --- +enum AlarmState { S0_Deactivated, S1_Activated, S2_TriggeredActive, S3_TriggeredInactive }; +AlarmState currentState = S0_Deactivated; +unsigned long s2StartTime = 0; +const unsigned long s2Timeout = 30 * 60 * 1000; // 30 minuten in ms +bool alarmInitialized = false; + +// --- 1-WIRE ADRESSEN (Vertaald uit Python dict) --- +uint8_t addr_Kast[] = { 0x28, 0xAA, 0x3D, 0x64, 0x40, 0x14, 0x01, 0xc3 }; // TempMeterKast +uint8_t addr_Thermostaat[] = { 0x28, 0xAA, 0x22, 0x64, 0x40, 0x14, 0x01, 0xd0 }; // TempThermostaat +uint8_t addr_Buiten[] = { 0x28, 0xAA, 0xB6, 0x4F, 0x40, 0x14, 0x01, 0x9c }; // TempBuiten +uint8_t addr_Kamer[] = { 0x28, 0xF0, 0x33, 0x79, 0x97, 0x11, 0x03, 0x13 }; // TempKamer +uint8_t addr_Overloop[] = { 0x28, 0x49, 0xA0, 0x79, 0x97, 0x14, 0x03, 0x92 }; // TempOverloop +uint8_t addr_Pi[] = { 0x28, 0x85, 0x4B, 0xB8, 0x0B, 0x00, 0x00, 0xCA }; // TempRaspberryPi +// Opmerking: De laatste byte (CRC) mag vaak 0x00 of 0xFF zijn als je ds.select() gebruikt, +// de DS2482 handelt de adressering af. + +// --- STATUS & TIMERS --- +unsigned long now; +unsigned long lastP1Read = 0; +unsigned long lastTempRead = 0; + +unsigned long relBelTimer = 0; +bool relBelActive = false; +unsigned long relCamTimer = 0; +bool relCamActive = false; + +int lastT1Door = HIGH, stableT1Door = HIGH; +int lastT2Act = HIGH, stableT2Act = HIGH; +unsigned long lastDbT1Door = 0, lastDbT2Act = 0; +const unsigned long dbDelay = 500; //500ms + +// --- P1 DATA VARIABELEN --- +float elDalVerbruikt, elPiekVerbruikt, elDalGeleverd, elPiekGeleverd; +float elHuidigVerbruik, elHuidigGeleverd, elGas; + + +WiFiClient espClient; +bool WifiConnected = false; + +PubSubClient mqttClient(espClient); +//AsyncWebServer server(80); +//WebSerial webSerial; +long lastReconnectAttempt = 0; +// Initialisatie DS2482 op standaard adres 0x18 +Adafruit_DS248x ds; +// Timing constants +unsigned long vorigeMillis = 0; +const long meetInterval = 60000; // Elke minuut nieuwe meting +bool metingBezig = false; + + +bool belRequest = false; +int fanRequest = -1; //-1=no_request, 0=disable, 1=enable +int enableAlarmRequest = -1; //-1=no_request, 0=disable, 1=enable +int buzzerRequest = -1; //-1=no_request, 0=disable, 1=enable +int lampRequest = -1; //-1=no_request, 0=disable, 1=enable +bool restartCameraRequest = false; +bool temp_initialised = false; +unsigned long lastWiFiCheck = 0; + +// We maken een nieuwe klasse die 'Print' overneemt +class DualOutput : public Print { + private: + String mqttBuffer = ""; // Buffer om een volledige regel te bouwen + String bootBuffer = ""; // Hier slaan we de logs op + bool bufferFull = false; // Om te voorkomen dat het geheugen volloopt + const size_t maxBufferSize = 2048; // Maximaal 2KB aan opstartlogs + + public: + // Dit is de magische functie waar alles doorheen gaat + size_t write(uint8_t character) override { + // 1. Schrijf naar de fysieke Seriële poort (USB) + size_t s = Serial.write(character); + + // 2. Bouw de regel op voor MQTT + if (character == '\n') { + // Alleen versturen als er een verbinding is en de buffer niet leeg is + if (mqttClient.connected() && mqttBuffer.length() > 0) { + mqttClient.publish(mqttTopicSerialOutput, mqttBuffer.c_str()); + } + mqttBuffer = ""; // Maak buffer leeg voor de volgende regel + } else if (character != '\r') + { // Negeer 'carriage return' + mqttBuffer += (char)character; + } + + // Beperk de bufferlengte om geheugenproblemen te voorkomen + if (mqttBuffer.length() > 150) mqttBuffer = ""; + + // // 3. Als er wel iemand kijkt, stuur het direct + // if (webSerial.getConnectionCount() > 0) { + // webSerial.write(character); + // } else if (!bufferFull) { + // bootBuffer += (char)character; + // if (bootBuffer.length() >= maxBufferSize) bufferFull = true; + // } + return s; + } + + // // Functie om de opgeslagen logs naar een nieuwe kijker te sturen + // void flushBuffer() { + // if (bootBuffer.length() > 0) { + // webSerial.println("--- Opgeslagen opstartlogs ---"); + // webSerial.print(bootBuffer); + // webSerial.println("--- Einde opstartlogs, live weergave gestart ---"); + // bootBuffer = ""; // Maak leeg na versturen om RAM vrij te maken + // } + // } +}; + +// Maak een object aan van je nieuwe klasse +DualOutput debuglog; + +void I2CScanner() +{ + debuglog.println("I2C scanner. Scanning ..."); + byte count = 0; + char buffer[50]; // Zorg dat de buffer groot genoeg is voor de hele tekst + + for (byte i = 1; i < 120; i++) + { + Wire.beginTransmission (i); + if (Wire.endTransmission () == 0) + { + snprintf(buffer, sizeof(buffer), "Found address: %d (0x%02X)", i, i); + debuglog.println(buffer); + count++; + delay (1); // maybe unneeded? + } // end of good response + } // end of for loop + snprintf(buffer, sizeof(buffer), "Scan done. Found %d device(s).", count); + debuglog.println(buffer); + +} + +void scanOneWireBus() { + uint8_t adresBuffer[8]; // Buffer voor het 64-bits (8 bytes) ROM adres + int aantalApparaten = 0; + + Serial.println("Scannen naar 1-Wire apparaten..."); + + // Reset de interne zoek-pointer van de DS248x + ds.OneWireSearchReset(); + + // Blijf zoeken zolang er nieuwe apparaten worden gevonden + while (ds.OneWireSearch(adresBuffer)) { + aantalApparaten++; + Serial.print("Gevonden apparaat "); + Serial.print(aantalApparaten); + Serial.print(": ROM = "); + + // Print het unieke adres in HEX-formaat + for (int i = 0; i < 8; i++) { + if (adresBuffer[i] < 16) Serial.print("0"); + Serial.print(adresBuffer[i], HEX); + Serial.print(" "); + } + + // Identificeer het type apparaat aan de hand van de Family Code (1e byte) + Serial.print(" -> Type: "); + if (adresBuffer[0] == 0x28) { + Serial.println("DS18B20 Temperatuursensor"); + } else if (adresBuffer[0] == 0x10) { + Serial.println("DS18S20 / DS1820 Sensor"); + } else { + Serial.print("Onbekend (Family Code: 0x"); + Serial.print(adresBuffer[0], HEX); + Serial.println(")"); + } + } + + if (aantalApparaten == 0) { + Serial.println("Geen 1-Wire apparaten gevonden op de bus."); + } else { + Serial.println("Scan voltooid."); + } +} + +void setupOta() +{ + debuglog.println("Setting up OTA"); + // Port defaults to 8266 + //ArduinoOTA.setPort(8266); + + // Hostname defaults to esp8266-[ChipID] + ArduinoOTA.setHostname("MeterKastController"); + + // No authentication by default + ArduinoOTA.setPassword((const char *)"tdsadmin"); + + ArduinoOTA.onStart([]() { + debuglog.println("OTA Start"); + }); + ArduinoOTA.onEnd([]() { + debuglog.println("\nOTA End"); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + debuglog.printf("OTA Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + debuglog.printf("OTA Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) debuglog.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) debuglog.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) debuglog.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) debuglog.println("Receive Failed"); + else if (error == OTA_END_ERROR) debuglog.println("End Failed"); + }); + ArduinoOTA.begin(); + debuglog.println("Ready"); + debuglog.print("IP address: "); + debuglog.println(WiFi.localIP()); + +} + +void sendMqttStatus(const char* topic, const char* val) { + mqttClient.publish(topic, val); +} + +void sendAlarmStatus(const char* status) +{ + debuglog.println(status); + mqttClient.publish(mqttTopicAlarmStatus, status); +} + +void sendP1Line(const char* line) +{ + debuglog.println(line); + mqttClient.publish(mqttTopicP1Line, line); +} + +void sendP1InvalidLine(const char* line) +{ + debuglog.println(line); + mqttClient.publish(mqttTopicP1InvalidLine, line); +} + +// states: +// S0=AlarmDeactivated +// S1=AlarmActivated +// S2=AlarmTriggeredMosfetActive +// S3=AlarmTriggeredMosfetInactive +// The transitions happen based on the two 12V inputs: DoorsOpen (T1Door), and AlarmActivated(T2Act) +// S0 -> T1Door -> S0 (mosfet stays inactive) +// S0 -> T2Act and T1Door active -> S2 {mosfet becomes active, send topic HcProtected with value1, send topic HcAlarm with value 1) +// S0 -> T2Act and T1Door inactive -> S1 (mosfet stays inactive, send topic HcProtected with value 1) +// S1 -> T1Door active -> S2 (mosfet becomes active, send topic HcAlarm with value 1) +// S1 -> T2Act inactive -> S0 (mosfet stays inactive, send topic HcProtected with value 0) +// S2 -> T2Act inactive -> S0 (moset becomes inactive, send topic HcProtected with value 0, send topic HcAlarm with value 0) +// S2 -> Ater 30min -> S3 (mosfet becomes inactive) +// S3 -> T1Door inactive -> S1 (mosfet stays inactive, send topic HcAlarm with value 0) +// S3 -> T2Act inactive -> S0 (moset stays inactive, send topic HcProtected with value 0, send topic HcAlarm with value 0) + +void SwitchVAlarm(bool aan) +{ + if (aan) + { + digitalWrite(PIN_VALARM, LOW); + sendMqttStatus(mqttTopicHcVAlarm, "1"); + } else + { + digitalWrite(PIN_VALARM, HIGH); + sendMqttStatus(mqttTopicHcVAlarm, "0"); + } +} + +void SwitchBuzzer(bool aan) +{ + if (aan) + { + digitalWrite(PIN_BUZZER, LOW); + sendMqttStatus(mqttTopicHcAlarmBuzzer, "1"); + } else + { + digitalWrite(PIN_BUZZER, HIGH); + sendMqttStatus(mqttTopicHcAlarmBuzzer, "0"); + } +} + +void SwitchAlarmLamp(bool aan) +{ + if (aan) + { + digitalWrite(PIN_ALARMLAMP, LOW); + sendMqttStatus(mqttTopicHcAlarmLamp, "1"); + } else + { + digitalWrite(PIN_ALARMLAMP, HIGH); + sendMqttStatus(mqttTopicHcAlarmLamp, "0"); + } +} + +void SwitchFan(bool aan) +{ + if (aan) + { + digitalWrite(PIN_FAN, LOW); + sendMqttStatus(mqttTopicFanMeterkast, "1"); + } else + { + digitalWrite(PIN_FAN, HIGH); + sendMqttStatus(mqttTopicFanMeterkast, "0"); + } +} + +void updateAlarmState() { + bool T1Door = (stableT1Door == LOW); // LOW = 12V aanwezig (Input Active) + bool T2Act = (stableT2Act == LOW); + + switch (currentState) { + case S0_Deactivated: + if (T2Act && !T1Door) { + currentState = S1_Activated; + sendAlarmStatus(" =>Deuren dicht, SL_aan=> : Alarm aangezet, alarm lampjes aan"); + sendMqttStatus(mqttTopicHcProtected, "1"); + SwitchAlarmLamp(true); + } else if (T2Act && T1Door) { + currentState = S2_TriggeredActive; + sendAlarmStatus("Deuren open, SL_aan=> : Alarm getriggered"); + s2StartTime = millis(); + SwitchBuzzer(true); + sendMqttStatus(mqttTopicHcProtected, "1"); + sendMqttStatus(mqttTopicHcAlarm, "1"); + } + break; + case S1_Activated: + if (T1Door) { //doors are opened + currentState = S2_TriggeredActive; + sendAlarmStatus(" =>Deuren open=> : Alarm getriggered, Alarm lampjes uit"); + s2StartTime = millis(); + SwitchBuzzer(true); + SwitchAlarmLamp(false); + sendMqttStatus(mqttTopicHcAlarm, "1"); + } else if (!T2Act) { //doors are closed + currentState = S0_Deactivated; + sendAlarmStatus(" =>Deuren dicht, SL_uit=> : Alarm uitgezet, Alarm lampjes uit"); + SwitchAlarmLamp(false); + sendMqttStatus(mqttTopicHcProtected, "0"); + sendMqttStatus(mqttTopicHcAlarm, "0"); + } + break; + + case S2_TriggeredActive: + if (!T2Act) { + currentState = S0_Deactivated; + sendAlarmStatus(" =>SL_uit=> : Alarm uitgezet, Alarm lampjes uit"); + SwitchBuzzer(false); + SwitchAlarmLamp(false); + sendMqttStatus(mqttTopicHcProtected, "0"); + sendMqttStatus(mqttTopicHcAlarm, "0"); + } else if (millis() - s2StartTime >= s2Timeout) { + if (T1Door) + { + currentState = S3_TriggeredInactive; + sendAlarmStatus(" =>Deuren open, SL_aan=> : Buzzer na timeout uitgezet"); + } else + { + currentState = S1_Activated; + sendAlarmStatus(" =>Deuren dicht, SL_aan=> : Buzzer na timeout uitgezet, Alarm weer aangezet, Alarm lampjes aan, Alarm untriggered"); + SwitchAlarmLamp(true); + sendMqttStatus(mqttTopicHcAlarm, "0"); + } + SwitchBuzzer(false); + } + break; + + case S3_TriggeredInactive: + if (!T1Door) { + currentState = S1_Activated; + sendAlarmStatus(" =>Deuren dicht, SL_aan=> : Deuren dicht, Alarm weer aangezet, Alarm lampjes aan, Alarm untriggered"); + SwitchAlarmLamp(true); + sendMqttStatus(mqttTopicHcAlarm, "0"); + } else if (!T2Act) { + currentState = S0_Deactivated; + sendAlarmStatus(" =>Deuren open, SL_uit=> : Alarm uitgezet, Alarm lampjes aan"); + SwitchAlarmLamp(false); + sendMqttStatus(mqttTopicHcProtected, "0"); + sendMqttStatus(mqttTopicHcAlarm, "0"); + } + break; + } +} + +void callback(char* topic, byte* payload, unsigned int length) { + debuglog.print("Topic received: "); + debuglog.println(topic); + if (strcmp(topic, mqttTopicBelVoorTest) == 0) { + belRequest = true; + } else if (strcmp(topic, mqttTopicRestarCamera) == 0) { + restartCameraRequest = true; + } else if (strcmp(topic, mqttTopicDisableVAlarm) == 0) { + enableAlarmRequest = 0; + } else if (strcmp(topic, mqttTopicEnableVAlarm) == 0) { + enableAlarmRequest = 1; + } else if (strcmp(topic, mqttTopicActivateFan) == 0) { + fanRequest = 1; + } else if (strcmp(topic, mqttTopicDeactivateFan) == 0) { + fanRequest = 0; + } else if (strcmp(topic, mqttTopicActivateBuzzer) == 0) { + buzzerRequest = 1; + } else if (strcmp(topic, mqttTopicDeactivateBuzzer) == 0) { + buzzerRequest = 0; + } else if (strcmp(topic, mqttTopicAlarmLampAan) == 0) { + lampRequest = 1; + } else if (strcmp(topic, mqttTopicAlarmLampUit) == 0) { + lampRequest = 0; + } +} + +void SetupTemperatureBel() +{ + // defaults are ok + // continuous mode, 12bit resolution, active high output for thermostat (not used) + Wire.beginTransmission(temp_addr_write); + Wire.write(0x51); //start convert + Wire.endTransmission( true ); + delay(800); //time required for first conversion, otherwise initial temp will be wrong +} + + + +void ReadTemperatureBel() +{ + int tempreg; + int msb_data; + int lsb_data; + // Receives data from the Temperature Register + Wire.beginTransmission(temp_addr_write); + Wire.write(0xAA); //switch to read register + Wire.endTransmission( false ); + + Wire.requestFrom(temp_addr_read, 2, true); + + msb_data = Wire.read(); + lsb_data = Wire.read(); + +// Debugprint("msb= "); +// Debugprint(String(msb_data, HEX)); +// Debugprint(" lsb= "); +// Debugprint(String(lsb_data, HEX)); + + tempreg = msb_data; + tempreg= tempreg << 8; + tempreg |= lsb_data; + +// Debugprint(" tempreg= "); +// Debugprint(String(tempreg, HEX)); + + int bit_set = tempreg & 0x8000; + + // two's complement + if (bit_set > 0) + { //make a negative number + temperature = -0.0625 * (float)((0xFFF - ((tempreg & 0xFFF0) >> 4)) + 1); + } else + { + temperature = 0.0625 * (float)((tempreg & 0x7FF0) >> 4); + } +// Debugprint(" shifted= "); +// Debugprint(String(((tempreg & 0x7FF0) >> 4), HEX)); +// Debugprint(" temperature= "); +// Debugprintln(temperature); +} + +void execute_bel_request() +{ + digitalWrite(PIN_RELAIS_BEL, LOW); + sendAlarmStatus(": PIN_RELAIS_BEL=>LOW"); + relBelTimer = millis(); + relBelActive = true; + belRequest = false; +} + +void handle_requests() { + if (belRequest) + { + execute_bel_request(); + } + if (restartCameraRequest) + { + digitalWrite(PIN_RELAIS_CAM, LOW); + sendAlarmStatus(": PIN_RELAIS_CAM=>LOW"); + relCamTimer = millis(); + relCamActive = true; + restartCameraRequest = false; + } + if (fanRequest >= 0) + { + if (fanRequest > 0) + { + digitalWrite(PIN_FAN, LOW); + sendAlarmStatus(": PIN_FAN=>LOW"); + sendMqttStatus(mqttTopicFanMeterkast, "1"); + } else + { + digitalWrite(PIN_FAN, LOW); + sendAlarmStatus(": PIN_FAN=>HIGH"); + sendMqttStatus(mqttTopicFanMeterkast, "0"); + } + fanRequest = -1; + } + if (buzzerRequest >= 0) + { + if (buzzerRequest > 0) + { + digitalWrite(PIN_BUZZER, LOW); + sendAlarmStatus(": PIN_BUZZER=>LOW"); + sendMqttStatus(mqttTopicHcAlarmBuzzer, "1"); + } else + { + digitalWrite(PIN_BUZZER, HIGH); + sendAlarmStatus(": PIN_BUZZER=>HIGH"); + sendMqttStatus(mqttTopicHcAlarmBuzzer, "0"); + } + buzzerRequest = -1; + } + if (enableAlarmRequest >= 0) + { + if (enableAlarmRequest > 0) + + { + digitalWrite(PIN_VALARM, LOW); + sendAlarmStatus(": PIN_VALARM=>LOW"); + sendMqttStatus(mqttTopicHcVAlarm, "1"); + } else + { + digitalWrite(PIN_VALARM, HIGH); + sendAlarmStatus(": PIN_VALARM=>HIGH"); + sendMqttStatus(mqttTopicHcVAlarm, "0"); + } + enableAlarmRequest = -1; + } + if (lampRequest >= 0) + { + if (lampRequest > 0) + + { + digitalWrite(PIN_ALARMLAMP, LOW); + sendAlarmStatus(": PIN_ALARMLAMP=>LOW"); + sendMqttStatus(mqttTopicHcAlarmLamp, "1"); + } else + { + digitalWrite(PIN_ALARMLAMP, HIGH); + sendAlarmStatus(": PIN_ALARMLAMP=>HIGH"); + sendMqttStatus(mqttTopicHcAlarmLamp, "0"); + } + lampRequest = -1; + } +} + +boolean reconnect() { + // Loop until we're reconnected + //debuglog.print("Attempting MQTT connection..."); + while (!mqttClient.connected()) { + if (WifiConnected) + { + debuglog.print("Attempting MQTT connection..."); + // Attempt to connect + if (mqttClient.connect(mqttClientId, mqttUser, mqttPassword)) { + debuglog.println("mqtt connected"); + // Once connected, publish an announcement... + //mqttClient.publish("outTopic", "hello world"); + // ... and resubscribe + delay(1000); + mqttClient.subscribe(mqttTopicBelVoorTest); + mqttClient.subscribe(mqttTopicRestarCamera); + mqttClient.subscribe(mqttTopicDisableVAlarm); + mqttClient.subscribe(mqttTopicEnableVAlarm); + mqttClient.subscribe(mqttTopicActivateFan); + mqttClient.subscribe(mqttTopicDeactivateFan); + mqttClient.subscribe(mqttTopicActivateBuzzer); + mqttClient.subscribe(mqttTopicDeactivateBuzzer); + mqttClient.subscribe(mqttTopicAlarmLampAan); + mqttClient.subscribe(mqttTopicAlarmLampUit); + return true; + } else { + debuglog.print("mqtt failed, rc="); + debuglog.print(mqttClient.state()); + debuglog.println(" try again soon..."); + return false; + } + } + } +} + +void handle_temperatures() +{ + unsigned long huidigeMillis = millis(); + + // STAP 1: Start de conversie voor ALLE sensoren tegelijk (Skip ROM) + if (!metingBezig && (huidigeMillis - vorigeMillis >= meetInterval)) { + debuglog.print("Starting all temp measurements..."); + startAlleMetingen(); + metingBezig = true; + vorigeMillis = huidigeMillis; + debuglog.println("Temp meting gestart..."); + } + + // STAP 2: Na 750ms zijn de sensoren klaar en lezen we ze één voor één uit + if (metingBezig && (huidigeMillis - vorigeMillis >= 800)) { // 800ms marge + debuglog.println("--- Nieuwe Metingen ---"); + float t = leesTemperatuur(addr_Kast); + if (t >-50) + { + debuglog.print("Meterkast: "); debuglog.println(t); + mqttClient.publish(mqttTopicTempMeterKast, String(t, 1).c_str()); + } + + t = leesTemperatuur(addr_Thermostaat); + if (t >-50) + { + debuglog.print("Thermostaat: "); debuglog.println(t); + mqttClient.publish(mqttTopicTempThermostaat, String(t, 1).c_str()); + } + + t = leesTemperatuur(addr_Buiten); + if (t >-50) + { + debuglog.print("Buiten: "); debuglog.println(t); + mqttClient.publish(mqttTopicTempBuiten, String(t, 1).c_str()); + } + + t = leesTemperatuur(addr_Kamer); + if (t >-50) + { + debuglog.print("Woonkamer: "); debuglog.println(t); + mqttClient.publish(mqttTopicTempKamer, String(t, 1).c_str()); + } + + t = leesTemperatuur(addr_Overloop); + if (t >-50) + { + debuglog.print("Overloop: "); debuglog.println(t); + mqttClient.publish(mqttTopicTempOverloop, String(t, 1).c_str()); + } + + t = leesTemperatuur(addr_Pi); + if (t >-50) + { + debuglog.print("Meterkast Controller: "); debuglog.println(t); + mqttClient.publish(mqttTopicTempMeterKastController, String(t, 1).c_str()); + } + + metingBezig = false; // Reset voor de volgende cyclus + debuglog.println("-----------------------"); + lastTempRead = now; + } +} + +void startAlleMetingen() { + ds.OneWireReset(); + ds.OneWireWriteByte(0xCC); // Skip ROM + ds.OneWireWriteByte(0x44); // Start Conversie +} + +float leesTemperatuur(uint8_t* adres) { + if (!ds.OneWireReset()) return -127.0; + // Adafruit gebruikt onewireWriteByte voor adressering + ds.OneWireWriteByte(0x55); + + // De 8 bytes van het adres één voor één versturen + for (uint8_t i = 0; i < 8; i++) { + ds.OneWireWriteByte(adres[i]); + } + + ds.OneWireWriteByte(0xBE); // Read Scratchpad commando + + + uint8_t data[9]; + for (int i = 0; i < 9; i++) { + ds.OneWireReadByte(&data[i]); + } + + // Controleer of de sensor aanwezig is (data[0] en [1] zijn niet 0xFF bij geldige data) + if (data[0] == 0xFF && data[1] == 0xFF) return -127.0; + + // Converteer bytes naar temperatuur + int16_t raw = (data[1] << 8) | data[0]; + return (float)raw / 16.0; +} + + +void handleInputs() { + int curT1 = digitalRead(PIN_INPUT_DOOR); + if (curT1 != lastT1Door) lastDbT1Door = millis(); + if ((millis() - lastDbT1Door) > dbDelay) { + if (curT1 != stableT1Door) { stableT1Door = curT1; updateAlarmState(); } + } + lastT1Door = curT1; + + int curT2 = digitalRead(PIN_INPUT_ACT); + if (curT2 != lastT2Act) lastDbT2Act = millis(); + if ((millis() - lastDbT2Act) > dbDelay) { + if (curT2 != stableT2Act) { stableT2Act = curT2; updateAlarmState(); } + } + lastT2Act = curT2; +} + +void handle_mqtt() +{ + if (!mqttClient.connected()) + { + long now = millis(); + if (now - lastReconnectAttempt > 5000) + { + lastReconnectAttempt = now; + // Attempt to reconnect + if (reconnect()) + { + lastReconnectAttempt = 0; + } + } + } else + { + mqttClient.loop(); + delay(10); + } +} + + +void readP1() { + digitalWrite(PIN_P1_REQ, HIGH); + unsigned long start = millis(); + bool line_is_valid = true; + while (millis() - start < 1500) { + if (Serial2.available()) { + String line = Serial2.readStringUntil('\n'); + //debuglog.print("Lengte van string: "); + //debuglog.println(line.length()); + //debuglog.print("P1 line: "); + //debuglog.println(line); + //sendP1Line(line); + line_is_valid = true; + if (line.startsWith("1-0:1.8.1")) sscanf(line.c_str(), "1-0:1.8.1(%f*kWh)", &elDalVerbruikt); + else if (line.startsWith("1-0:1.8.2")) sscanf(line.c_str(), "1-0:1.8.2(%f*kWh)", &elPiekVerbruikt); + else if (line.startsWith("1-0:2.8.1")) sscanf(line.c_str(), "1-0:2.8.1(%f*kWh)", &elDalGeleverd); + else if (line.startsWith("1-0:2.8.2")) sscanf(line.c_str(), "1-0:2.8.2(%f*kWh)", &elPiekGeleverd); + else if (line.startsWith("1-0:1.7.0")) sscanf(line.c_str(), "1-0:1.7.0(%f*kW)", &elHuidigVerbruik); + else if (line.startsWith("1-0:2.7.0")) sscanf(line.c_str(), "1-0:2.7.0(%f*kW)", &elHuidigGeleverd); + else if (line.startsWith("0-1:24.2.1")) { + // Gas is lastiger: (tijd)(waarde) -> we zoeken de laatste '(' + int lastParen = line.lastIndexOf('('); + if (lastParen != -1) { + sscanf(line.substring(lastParen).c_str(), "(%f*m3)", &elGas); + } + } else + { + line_is_valid = false; + } + if (line_is_valid) + { + sendP1Line(line.c_str()); + } else + { + sendP1InvalidLine(line.c_str()); + } + if (line.startsWith("!")) break; + } else { + //sendP1InvalidLine("Serial is not available, can not read"); + //debuglog.println("Serial2 is not available, can not read P1"); + } + } + digitalWrite(PIN_P1_REQ, LOW); + mqttClient.publish(mqttTopicDalVerbruikt, String(elDalVerbruikt).c_str()); + mqttClient.publish(mqttTopicPiekVerbruikt, String(elPiekVerbruikt).c_str()); + mqttClient.publish(mqttTopicDalGeleverd, String(elDalGeleverd).c_str()); + mqttClient.publish(mqttTopicPiekGeleverd, String(elPiekGeleverd).c_str()); + mqttClient.publish(mqttTopicHuidigVerbruik, String(elHuidigVerbruik).c_str()); + mqttClient.publish(mqttTopicHuidigGeleverd, String(elHuidigGeleverd).c_str()); + mqttClient.publish(mqttTopicGasTotaal, String(elGas).c_str()); +} + +void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { + switch (event) + { + case ARDUINO_EVENT_WIFI_STA_CONNECTED: + Serial.println("Verbonden met de router, still no ip!"); + break; + + case ARDUINO_EVENT_WIFI_STA_GOT_IP: + Serial.print("IP-adres ontvangen: "); + Serial.println(WiFi.localIP()); + WifiConnected = true; + wifiRestarted = true; + break; + + case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: + WifiConnected = false; + Serial.print("Disconnected! Reason: "); + Serial.println(info.wifi_sta_disconnected.reason); + //wifiNeedsRestart = true; + // Dwing een reconnect, zelfs als de eerste poging faalde + //Serial.println("Opnieuw proberen..."); + //WiFi.begin(); + break; + + default: + break; + } +} + +void handleWifiRestart() +{ + if (wifiNeedsRestart) + { + wifiNeedsRestart = false; + debuglog.println("Retrying to connect to WiFi"); + WiFi.begin(ssid, password); + } else if (wifiRestarted) + { + wifiRestarted = false; + setupOta(); + reconnect(); + // IP ophalen + String ipAdres = WiFi.localIP().toString(); + String url = "MeterKastController: " + ipAdres; + sendAlarmStatus(url.c_str()); + } +} + +void PublishBelMQtt(int counter) +{ + //char result[20] = ""; + sprintf(result, "%i\0", counter); + if (!mqttClient.publish(mqtt_bel_topic, result)) + { + debuglog.println("Bel message failed to send"); + } +} + +void PublishTemperatureMQtt(float temperature) +{ + //char result[20] = ""; + sprintf(result, "Temp C: %.2f\0", temperature); + + if (!mqttClient.publish(mqtt_temperature_topic, result)) + { + debuglog.println("Temperature message failed to send."); + } +} + +void PublishBoxStateMQtt(int boxState) +{ + //char result[20] = ""; + sprintf(result, "%i\0", boxState); + if (!mqttClient.publish(mqtt_box_state_topic, result)) + { + debuglog.println("Box state message failed to send."); + } +} + +void PublishBelStateMQtt(int belState) +{ + //char result[20] = ""; + sprintf(result, "%i\0", belState); + if (!mqttClient.publish(mqtt_bel_state_topic, result)) + { + debuglog.println("Bel state message failed to send."); + } +} + +void PublishInfoMQtt(int belState, int boxState, float temperature) +{ + //char result[30] = ""; + sprintf(result, "{'Temp': %.2f, 'Bel':%i, 'Box':%i, 'Wifi':%i}\0", temperature, belState, boxState, WiFi.RSSI()); + + if (!mqttClient.publish(mqtt_info_topic, result)) + { + + debuglog.println("Info message failed to send."); + } + +} + +void SendBoxOpenedToClients(int numberOfInterruptsBox) +{ + //char result[20] = ""; + sprintf(result, "%i\0", numberOfInterruptsBox); + if (!mqttClient.publish(mqtt_box_opened_topic, result)) + { + debuglog.println("Box opened message failed to send."); + } +} + +void SendBoxClosedToClients(int numberOfInterruptsBox) +{ + //char result[20] = ""; + sprintf(result, "%i\0", numberOfInterruptsBox); + if (!mqttClient.publish(mqtt_box_closed_topic, result)) + { + debuglog.println("Box closed message failed to send."); + } +} + +void SendDeBelGaatToClients(int counter) +{ + PublishBelMQtt(counter); +} + +void update_box_state() +{ + char buffer[50]; + prev_boxState = boxState; + boxState = digitalRead(PIN_BOX); + box_readoutTime = millis(); + if (prev_boxState != boxState) + { + PublishBoxStateMQtt(boxState); + // Display the box state in the Serial Monitor + if (boxState > 0) + { + snprintf(buffer, sizeof(buffer), "Box State = %d Brievenbus opened", boxState); + debuglog.println(buffer); + SendBoxOpenedToClients(numberOfInterruptsBox); + } else + { + snprintf(buffer, sizeof(buffer), "Box State = %d Brievenbus closed", boxState); + debuglog.println(buffer); + SendBoxClosedToClients(numberOfInterruptsBox); + } + PublishInfoMQtt(belState, boxState, temperature); + } +} + +void update_bel_state() +{ + char buffer[50]; + prev_belState = belState; + belState = digitalRead(PIN_BEL); + bel_readoutTime = millis(); + if (prev_belState != belState) + { + execute_bel_request(); + + PublishBelStateMQtt(belState); + // Display the bel state in the Serial Monitor + if (belState > 0) + { + snprintf(buffer, sizeof(buffer), "Bel State = %d De bel gaat uit", belState); + debuglog.println(buffer); + //SendBoxClosedToClients(numberOfInterruptsBox); + } else + { + snprintf(buffer, sizeof(buffer), "Bel State = %d De bel gaat", belState); + debuglog.println(buffer); + SendDeBelGaatToClients(numberOfInterruptsBel); + } + PublishInfoMQtt(belState, boxState, temperature); + } +} + +void HandelBelInterrupt() +{ + char buffer[50]; + if(interruptCounterBel > 0) + { + interruptCounterBel = 0; + // if ((millis() - lastDebounceTimeBel) > debounceDelayBel) + // { + // reset the debouncing timer + // lastDebounceTimeBel = millis(); + + numberOfInterruptsBel++; + + snprintf(buffer, sizeof(buffer), "An Bel interrupt has occurred. Total: %d", numberOfInterruptsBel); + debuglog.println(buffer); + update_bel_state(); + //SendDeBelGaatToClients(numberOfInterruptsBel); + // } + } +} + +void HandelBoxInterrupt() +{ + char buffer[50]; + if(interruptCounterBox > 0) + { + interruptCounterBox = 0; + // if ((millis() - lastDebounceTimeBox) > debounceDelayBox) + // { + // reset the debouncing timer + // lastDebounceTimeBox = millis(); + + numberOfInterruptsBox++; + + snprintf(buffer, sizeof(buffer), "An Box interrupt has occurred. Total: %d", numberOfInterruptsBox); + debuglog.println(buffer); + update_box_state(); + // } + } +} + +void HandleTemperatureBel() +{ + char buffer[50]; + if ((millis() - temp_readoutTime) > 30000) + { + float prev_temperature = temperature; + ReadTemperatureBel(); + temp_readoutTime = millis(); + if (prev_temperature != temperature) + { + PublishTemperatureMQtt(temperature); + // Display the temperature in the Serial Monitor + snprintf(buffer, sizeof(buffer), "Temp = %0.2f C", temperature); + debuglog.println(buffer); + PublishInfoMQtt(belState, boxState, temperature); + } + } +} + +void HandleBelState() +{ + if ((millis() - bel_readoutTime) > 500) + { + update_bel_state(); + } +} + +void HandleBoxState() +{ + if ((millis() - box_readoutTime) > 500) + { + update_box_state(); + } +} + +void HandleBelInfo() +{ + if ((millis() - info_Time) > 30000) + { + info_Time = millis(); + PublishInfoMQtt(belState, boxState, temperature); + } +} + +void HandleBelBox() +{ + HandelBelInterrupt(); + HandelBoxInterrupt(); + HandleTemperatureBel(); + HandleBelState(); + HandleBoxState(); + HandleBelInfo(); +} + +// Taak uitvoeren op tweede Core, zodat deze doro blijft lopen als wifi disconnected is (sensoren uitlezen, etc.) +void SensorAndAlarmTaskTask(void * pvParameters) { + for(;;) { + HandleBelBox(); + handle_requests(); + + if (relBelActive && (millis() - relBelTimer >= 200)) { + digitalWrite(PIN_RELAIS_BEL, HIGH); + sendAlarmStatus(": PIN_RELAIS_BEL=>HIGH"); + relBelActive = false; + } + if (relCamActive && (millis() - relCamTimer >= 5000)) { + digitalWrite(PIN_RELAIS_CAM, HIGH); + sendAlarmStatus(": PIN_RELAIS_CAM=>HIGH"); + relCamActive = false; + } + + if (!alarmInitialized) + { + debuglog.println("Determine initial alarm state"); + updateAlarmState(); + alarmInitialized = true; + } else{ + if (currentState == S2_TriggeredActive) updateAlarmState(); // Check timeout voor S2 -> S3 + } + + handleInputs(); + + now = millis(); + + if (temp_initialised) + { + handle_temperatures(); + } + + + if (now - lastP1Read > 10000) { readP1(); lastP1Read = now; } + } +} + +void setup() { + Serial.begin(115200); + Serial2.begin(115200, SERIAL_8N1, 16, -1, true); + pinMode(PIN_BUZZER, OUTPUT); + pinMode(PIN_FAN, OUTPUT); + pinMode(PIN_VALARM, OUTPUT); + pinMode(PIN_ALARMLAMP, OUTPUT); + pinMode(PIN_RELAIS_BEL, OUTPUT); + pinMode(PIN_RELAIS_CAM, OUTPUT); + pinMode(PIN_P1_REQ, OUTPUT); + pinMode(PIN_INPUT_DOOR, INPUT_PULLUP); + pinMode(PIN_INPUT_ACT, INPUT_PULLUP); + + + digitalWrite(PIN_BUZZER, HIGH); + digitalWrite(PIN_FAN, HIGH); + digitalWrite(PIN_VALARM, LOW); + digitalWrite(PIN_ALARMLAMP, HIGH); + + digitalWrite(PIN_RELAIS_BEL, HIGH); + digitalWrite(PIN_RELAIS_CAM, HIGH); + + pinMode(PIN_BEL, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(PIN_BEL), handleInterruptbel, CHANGE); + pinMode(PIN_BOX, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(PIN_BOX), handleInterruptbox, CHANGE); + lastDebounceTimeBel = millis(); + lastDebounceTimeBox = millis(); + + Wire.begin(PIN_SDA, PIN_SCL); //by default use sda=21 and scl=22 + Wire.setClock(400000); // Zet I2C snelheid op 400kHz voor strakkere timing + I2CScanner(); + + //Wire.begin(21, 22); //by default use sda=21 and scl=22 + if (!ds.begin(&Wire, DS248X_ADDRESS)) { + temp_initialised = false; + sendAlarmStatus("DS2482-100 initialization failed."); + } else + { + temp_initialised = true; + sendAlarmStatus("DS2482-100 initialization OK!"); + + scanOneWireBus(); + + // Speed up I2C, as searching for ROMs, specifically, is slow! + //Wire.setClock(400000); + //debuglog.println("DS2482 geinitialiseerd wirespeed increased."); + } + + SetupTemperatureBel(); + + // 1. Maak een aparte, onafhankelijke taak aan voor jouw code op Core 1 + xTaskCreatePinnedToCore( + SensorAndAlarmTaskTask, // De functie hierboven + "AalarmTask", // Naam van de taak + 4096, // Geheugengrootte (stack size) + NULL, // Parameters + 1, // Prioriteit + NULL, // Task handle + 1 // Forceer uitvoering op Core 1 (WiFi zit op Core 0) + ); + + mqttClient.setServer(mqtt_server, mqttPort); + mqttClient.setCallback(callback); + + debuglog.println("Setting up WiFi"); + + WiFi.onEvent(WiFiEvent); // Register the event handler + WiFi.disconnect(true, true); + delay(1000); + WiFi.mode(WIFI_STA); + //WiFi.setSleep(false); //Dit houdt de radio stabieler op één vermogensniveau, wat soms helpt bij "Reason 2" fouten + WiFi.setAutoReconnect(true); + esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G); // Schakel 'N' uit, Forceer stabiele protocollen (B/G) + debuglog.println("Trying to connect to WiFi"); + WiFi.begin(ssid, password); + + + // while (WiFi.waitForConnectResult() != WL_CONNECTED) { + // debuglog.println("Connection Failed! Rebooting..."); + // delay(5000); + // ESP.restart(); + // } + // 2. Pas nu webSerial en Server initialiseren + //webSerial.begin(&server); + //server.begin(); + + //setupOta(); + lastReconnectAttempt = 0; + + +} + +void loop() { + //handleWifi(); + //if (!bufferVerstuurd && webSerial.getConnectionCount() > 0) { + // debuglog.flushBuffer(); + // bufferVerstuurd = true; + //} + handleWifiRestart(); + if (WiFi.status() == WL_CONNECTED) + { + ArduinoOTA.handle(); + handle_mqtt(); + } else + { + // Geef de processor rust als er geen WiFi is + delay(100); + } +}