ampel-firmware.ino 6.39 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/***
 *       ____ ___ ____       _                         _
 *      / ___/ _ \___ \     / \   _ __ ___  _ __   ___| |
 *     | |  | | | |__) |   / _ \ | '_ ` _ \| '_ \ / _ \ |
 *     | |__| |_| / __/   / ___ \| | | | | | |_) |  __/ |
 *      \____\___/_____| /_/__ \_\_| |_| |_| .__/ \___|_|         _
 *     | | | |/ _|_   _| / ___|| |_ _   _| |_| |_ __ _  __ _ _ __| |_
 *     | |_| | |_  | |   \___ \| __| | | | __| __/ _` |/ _` | '__| __|
 *     |  _  |  _| | |    ___) | |_| |_| | |_| || (_| | (_| | |  | |_
 *     |_| |_|_|   |_|   |____/ \__|\__,_|\__|\__\__, |\__,_|_|   \__|
 *                                               |___/
 */

14
#include "ampel-firmware.h"
15
16
17
18
19

/*****************************************************************
 * GPL License                                                   *
 *****************************************************************/
/*
Eric Duminil's avatar
Eric Duminil committed
20
21
 * 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 )
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 * 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 <http://www.gnu.org/licenses/>.
 */

/*****************************************************************
 * Authors                                                       *
 *****************************************************************/
/*
 * Eric Duminil
 * Robert Otto
 * Myriam Guedey
 * Tobias Gabriel Erhart
 * Jonas Stave
 */

/*****************************************************************
 * 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() {
62
63
  led_effects::setupOnBoardLED();
  led_effects::onBoardLEDOff();
64
65
66

  Serial.begin(BAUDS);

67
  pinMode(0, INPUT); // Flash button (used for forced calibration)
68

69
  led_effects::setupRing();
70
71
72
73
74
75
76
77

  sensor::initialize();

  Serial.print(F("Sensor ID: "));
  Serial.println(SENSOR_ID);
  Serial.print(F("Board    : "));
  Serial.println(BOARD);

Eric Duminil's avatar
Eric Duminil committed
78
#ifdef AMPEL_WIFI
79
80
81
82
83
84
85
  // Try to connect to Wi-Fi
  WiFiConnect(SENSOR_ID);

  Serial.print(F("WiFi STATUS: "));
  Serial.println(WiFi.status());

  if (WiFi.status() == WL_CONNECTED) {
Eric Duminil's avatar
Eric Duminil committed
86
#  ifdef AMPEL_HTTP
87
    web_server::initialize();
Eric Duminil's avatar
Eric Duminil committed
88
#  endif
89
90
91
92
93
94
95
96
97
98

    ntp::initialize();

    if (MDNS.begin(SENSOR_ID.c_str())) { // Start the mDNS responder for SENSOR_ID.local
      MDNS.addService("http", "tcp", 80);
      Serial.println(F("mDNS responder started"));
    } else {
      Serial.println(F("Error setting up MDNS responder!"));
    }

Eric Duminil's avatar
Eric Duminil committed
99
#  ifdef AMPEL_MQTT
100
    mqtt::initialize("CO2sensors/" + SENSOR_ID);
Eric Duminil's avatar
Eric Duminil committed
101
#  endif
102
  }
Eric Duminil's avatar
Eric Duminil committed
103
#endif
Eric Duminil's avatar
Eric Duminil committed
104

Eric Duminil's avatar
Eric Duminil committed
105
#ifdef AMPEL_CSV
106
  csv_writer::initialize();
107
#endif
Eric Duminil's avatar
Eric Duminil committed
108

Eric Duminil's avatar
Eric Duminil committed
109
#if defined(AMPEL_LORAWAN) && defined(ESP32)
Eric Duminil's avatar
Eric Duminil committed
110
111
  lorawan::initialize();
#endif
112
113
114
115
116
117
118
}

/*****************************************************************
 * Main loop                                                     *
 *****************************************************************/

void loop() {
Eric Duminil's avatar
Eric Duminil committed
119
#if defined(AMPEL_LORAWAN) && defined(ESP32)
Eric Duminil's avatar
Eric Duminil committed
120
121
122
123
124
125
126
127
  //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
128
129
130
131
132
  //NOTE: Loop should never take more than 1000ms. Split in smaller methods and logic if needed.
  //TODO: Restart every day or week, in order to not let t0 overflow?
  uint32_t t0 = millis();

  keepServicesAlive();
133

134
135
136
  // Short press for night mode, Long press for calibration.
  checkFlashButton();

Eric Duminil's avatar
Eric Duminil committed
137
  if (sensor::processData()) {
Eric Duminil's avatar
Eric Duminil committed
138
#ifdef AMPEL_CSV
Eric Duminil's avatar
Eric Duminil committed
139
140
141
    csv_writer::logIfTimeHasCome(sensor::timestamp, sensor::co2, sensor::temperature, sensor::humidity);
#endif

Eric Duminil's avatar
Eric Duminil committed
142
#if defined(AMPEL_WIFI) && defined(AMPEL_MQTT)
Eric Duminil's avatar
Eric Duminil committed
143
144
145
    mqtt::publishIfTimeHasCome(sensor::timestamp, sensor::co2, sensor::temperature, sensor::humidity);
#endif

Eric Duminil's avatar
Eric Duminil committed
146
#if defined(AMPEL_LORAWAN) && defined(ESP32)
Eric Duminil's avatar
Eric Duminil committed
147
    lorawan::preparePayloadIfTimeHasCome(sensor::co2, sensor::temperature, sensor::humidity);
Eric Duminil's avatar
Eric Duminil committed
148
149
#endif
  }
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

  uint32_t duration = millis() - t0;
  if (duration > max_loop_duration) {
    max_loop_duration = duration;
    Serial.print("Max loop duration : ");
    Serial.print(max_loop_duration);
    Serial.println(" ms.");
  }
}

/**
 * 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
168
    led_effects::onBoardLEDOn();
169
170
171
    delay(300);
    if (digitalRead(0)) {
      Serial.println(F("Flash has been pressed for a short time. Should toggle night mode."));
172
      led_effects::toggleNightMode();
173
174
    } else {
      Serial.println(F("Flash has been pressed for a long time. Keep it pressed for calibration."));
175
      if (led_effects::countdownToZero() < 0) {
176
177
178
        sensor::startCalibrationProcess();
      }
    }
179
    led_effects::onBoardLEDOff();
180
181
182
183
  }
}

void keepServicesAlive() {
Eric Duminil's avatar
Eric Duminil committed
184
#ifdef AMPEL_WIFI
185
  if (WiFi.status() == WL_CONNECTED) {
Eric Duminil's avatar
Eric Duminil committed
186
#  if defined(ESP8266)
187
188
189
    //NOTE: Sadly, there seems to be a bug in the current MDNS implementation.
    // It stops working after 2 minutes. And forcing a restart leads to a memory leak.
    MDNS.update();
Eric Duminil's avatar
Eric Duminil committed
190
#  endif
191
    ntp::update(); // NTP client has its own timer. It will connect to NTP server every 60s.
Eric Duminil's avatar
Eric Duminil committed
192
#  ifdef AMPEL_HTTP
193
    web_server::update();
Eric Duminil's avatar
Eric Duminil committed
194
195
#  endif
#  ifdef AMPEL_MQTT
196
    mqtt::keepConnection(); // MQTT client has its own timer. It will keep alive every 15s.
Eric Duminil's avatar
Eric Duminil committed
197
#  endif
198
  }
Eric Duminil's avatar
Eric Duminil committed
199
#endif
200
}