/*** * ____ ___ ____ _ _ * / ___/ _ \___ \ / \ _ __ ___ _ __ ___| | * | | | | | |__) | / _ \ | '_ ` _ \| '_ \ / _ \ | * | |__| |_| / __/ / ___ \| | | | | | |_) | __/ | * \____\___/_____| /_/__ \_\_| |_| |_| .__/ \___|_| _ * | | | |/ _|_ _| / ___|| |_ _ _| |_| |_ __ _ __ _ _ __| |_ * | |_| | |_ | | \___ \| __| | | | __| __/ _` |/ _` | '__| __| * | _ | _| | | ___) | |_| |_| | |_| || (_| | (_| | | | |_ * |_| |_|_| |_| |____/ \__|\__,_|\__|\__\__, |\__,_|_| \__| * |___/ */ #include "ampel-firmware.h" /***************************************************************** * GPL License * *****************************************************************/ /* * This file is part of the "CO2 Ampel" project ( https://transfer.hft-stuttgart.de/gitlab/co2ampel and * https://transfer.hft-stuttgart.de/gitlab/co2ampel/ampel-firmware ) * Copyright (c) 2020 HfT Stuttgart. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /***************************************************************** * Authors * *****************************************************************/ /* * Eric Duminil * Robert Otto * Myriam Guedey * Tobias Gabriel Erhart * Jonas Stave * Michael Käppler */ /***************************************************************** * Configuration * *****************************************************************/ /* * Please define settings in 'config.h'. * There's an example config file called 'config.example.h'. * You can copy 'config.public.h' (stored in Git) to 'config.h' (not stored in Git), * and define your credentials and parameters in 'config.h'. */ /***************************************************************** * Setup * *****************************************************************/ void setup() { led_effects::setupOnBoardLED(); led_effects::onBoardLEDOff(); Serial.begin(BAUDS); pinMode(0, INPUT); // Flash button (used for forced calibration) Serial.println(); Serial.print(F("Sensor ID: ")); Serial.println(ampel.sensorId); Serial.print(F("Board : ")); Serial.println(ampel.board); Serial.print(F("Firmware : ")); Serial.println(ampel.version); led_effects::setupRing(); sensor::initialize(); #ifdef AMPEL_CSV csv_writer::initialize(ampel.sensorId); #endif #ifdef AMPEL_WIFI // wifi::connect(ampel.sensorId); // Serial.print(F("WiFi - Status: ")); // Serial.println(WiFi.status()); # ifdef AMPEL_HTTP web_server::initialize(); # endif #endif #if defined(AMPEL_LORAWAN) && defined(ESP32) lorawan::initialize(); #endif } /***************************************************************** * Helper functions * *****************************************************************/ void keepServicesAlive(); void checkFlashButton(); void checkSerialInput(); /***************************************************************** * Main loop * *****************************************************************/ void loop() { #if defined(AMPEL_LORAWAN) && defined(ESP32) //LMIC Library seems to be very sensitive to timing issues, so run it first. lorawan::process(); if (lorawan::waiting_for_confirmation) { // If node is waiting for join confirmation from Gateway, nothing else should run. return; } #endif //NOTE: Loop should never take more than 1000ms. Split in smaller methods and logic if needed. //NOTE: Only use millis() for duration comparison, not timestamps comparison. Otherwise, problems happen when millis roll over. uint32_t t0 = millis(); keepServicesAlive(); // Short press for night mode, Long press for calibration. checkFlashButton(); checkSerialInput(); if (sensor::processData()) { #ifdef AMPEL_CSV csv_writer::logIfTimeHasCome(sensor::timestamp, sensor::co2, sensor::temperature, sensor::humidity); #endif #if defined(AMPEL_WIFI) && defined(AMPEL_MQTT) mqtt::publishIfTimeHasCome(sensor::timestamp, sensor::co2, sensor::temperature, sensor::humidity); #endif #if defined(AMPEL_LORAWAN) && defined(ESP32) lorawan::preparePayloadIfTimeHasCome(sensor::co2, sensor::temperature, sensor::humidity); #endif } uint32_t duration = millis() - t0; if (duration > ampel.max_loop_duration) { ampel.max_loop_duration = duration; Serial.print(F("Debug - Max loop duration : ")); Serial.print(ampel.max_loop_duration); Serial.println(F(" ms.")); } } void checkSerialInput() { while (Serial.available() > 0) { sensor_console::processSerialInput(Serial.read()); } } /** * Checks if flash button has been pressed: * If not, do nothing. * If short press, toggle LED display. * If long press, start calibration process. */ void checkFlashButton() { if (!digitalRead(0)) { // Button has been pressed led_effects::onBoardLEDOn(); delay(300); if (digitalRead(0)) { Serial.println(F("Flash has been pressed for a short time. Should toggle night mode.")); led_effects::toggleNightMode(); } else { Serial.println(F("Flash has been pressed for a long time. Keep it pressed for calibration.")); if (led_effects::countdownToZero() < 0) { sensor::startCalibrationProcess(); } } led_effects::onBoardLEDOff(); } } void keepServicesAlive() { #ifdef AMPEL_WIFI # ifdef AMPEL_HTTP web_server::update(); # endif #endif }