Commit 67301e9e authored by Eric Duminil's avatar Eric Duminil
Browse files

Merge branch 'refactor/dependencies' into develop

parents 649d7fdf 6149cce2
Pipeline #5749 failed with stage
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#endif #endif
#include "util.h" #include "util.h"
#include "ntp.h"
#include "sensor_console.h" #include "sensor_console.h"
#include "co2_sensor.h" #include "co2_sensor.h"
#include "led_effects.h" #include "led_effects.h"
......
...@@ -88,10 +88,7 @@ void setup() { ...@@ -88,10 +88,7 @@ void setup() {
#ifdef AMPEL_WIFI #ifdef AMPEL_WIFI
wifi::connect(ampel.sensorId); wifi::connect(ampel.sensorId);
Serial.print(F("WiFi - Status: ")); if (wifi::connected()) {
Serial.println(WiFi.status());
if (WiFi.status() == WL_CONNECTED) {
# ifdef AMPEL_HTTP # ifdef AMPEL_HTTP
web_server::initialize(); web_server::initialize();
# endif # endif
...@@ -203,7 +200,7 @@ void checkFlashButton() { ...@@ -203,7 +200,7 @@ void checkFlashButton() {
void keepServicesAlive() { void keepServicesAlive() {
#ifdef AMPEL_WIFI #ifdef AMPEL_WIFI
if (WiFi.status() == WL_CONNECTED) { if (wifi::connected()) {
# if defined(ESP8266) # if defined(ESP8266)
//NOTE: Sadly, there seems to be a bug in the current MDNS implementation. //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. // It stops working after 2 minutes. And forcing a restart leads to a memory leak.
......
#include "co2_sensor.h" #include "co2_sensor.h"
#include "config.h"
#include "ntp.h"
#include "led_effects.h"
#include "sensor_console.h"
#include <Wire.h>
namespace config { namespace config {
// UPPERCASE values should be defined in config.h // UPPERCASE values should be defined in config.h
uint16_t measurement_timestep = MEASUREMENT_TIMESTEP; // [s] Value between 2 and 1800 (range for SCD30 sensor). uint16_t measurement_timestep = MEASUREMENT_TIMESTEP; // [s] Value between 2 and 1800 (range for SCD30 sensor).
......
...@@ -4,11 +4,6 @@ ...@@ -4,11 +4,6 @@
// The SCD30 from Sensirion is a high quality Nondispersive Infrared (NDIR) based CO₂ sensor capable of detecting 400 to 10000ppm with an accuracy of ±(30ppm+3%). // The SCD30 from Sensirion is a high quality Nondispersive Infrared (NDIR) based CO₂ sensor capable of detecting 400 to 10000ppm with an accuracy of ±(30ppm+3%).
// https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library // https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
#include "src/lib/SparkFun_SCD30_Arduino_Library/src/SparkFun_SCD30_Arduino_Library.h" // From: http://librarymanager/All#SparkFun_SCD30 #include "src/lib/SparkFun_SCD30_Arduino_Library/src/SparkFun_SCD30_Arduino_Library.h" // From: http://librarymanager/All#SparkFun_SCD30
#include "config.h"
#include "led_effects.h"
#include "util.h"
#include "sensor_console.h"
#include <Wire.h>
namespace config { namespace config {
extern uint16_t measurement_timestep; // [s] Value between 2 and 1800 (range for SCD30 sensor) extern uint16_t measurement_timestep; // [s] Value between 2 and 1800 (range for SCD30 sensor)
......
...@@ -119,10 +119,7 @@ ...@@ -119,10 +119,7 @@
*/ */
// 1) Requires "MCCI LoRaWAN LMIC library", which will be automatically used with PlatformIO but should be added in "Arduino IDE". // 1) Requires "MCCI LoRaWAN LMIC library", which will be automatically used with PlatformIO but should be added in "Arduino IDE".
// 2) Region and transceiver type should be specified in: // 2) If you need to, region and transceiver type can be specified in lorawan.cpp. Default is "Europe 868"
// * Arduino/libraries/MCCI_LoRaWAN_LMIC_library/project_config/lmic_project_config.h for Arduino IDE
// * platformio.ini for PlatformIO
// See https://github.com/mcci-catena/arduino-lmic#configuration for more information
// 3) It has been tested with "TTGO ESP32 SX1276 LoRa 868" and will only work with an ESP32 + LoRa modem // 3) It has been tested with "TTGO ESP32 SX1276 LoRa 868" and will only work with an ESP32 + LoRa modem
// 4) In order to use LoRaWAN, a gateway should be close to the co2ampel, and an account, an application and a device should be registered, // 4) In order to use LoRaWAN, a gateway should be close to the co2ampel, and an account, an application and a device should be registered,
// e.g. on https://www.thethingsnetwork.org/docs/applications/ // e.g. on https://www.thethingsnetwork.org/docs/applications/
......
#include "csv_writer.h" #include "csv_writer.h"
#include "config.h"
#include "ntp.h"
#include "led_effects.h"
#include "sensor_console.h"
namespace config { namespace config {
// Values should be defined in config.h // Values should be defined in config.h
uint16_t csv_interval = CSV_INTERVAL; // [s] uint16_t csv_interval = CSV_INTERVAL; // [s]
......
...@@ -11,11 +11,6 @@ ...@@ -11,11 +11,6 @@
# error Board should be either ESP8266 or ESP832 # error Board should be either ESP8266 or ESP832
#endif #endif
#include "config.h"
#include "util.h"
#include "led_effects.h"
#include "sensor_console.h"
namespace config { namespace config {
extern uint16_t csv_interval; // [s] extern uint16_t csv_interval; // [s]
} }
......
#include "led_effects.h" #include "led_effects.h"
#include "config.h"
#include "sensor_console.h"
// Adafruit NeoPixel (Arduino library for controlling single-wire-based LED pixels and strip)
// https://github.com/adafruit/Adafruit_NeoPixel
// Documentation : http://adafruit.github.io/Adafruit_NeoPixel/html/class_adafruit___neo_pixel.html
#include "src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h"
/***************************************************************** /*****************************************************************
* Configuration * * Configuration *
*****************************************************************/ *****************************************************************/
......
#ifndef LED_EFFECTS_H_INCLUDED #ifndef LED_EFFECTS_H_INCLUDED
#define LED_EFFECTS_H_INCLUDED #define LED_EFFECTS_H_INCLUDED
#include <Arduino.h>
#include "config.h"
#include "sensor_console.h"
// Adafruit NeoPixel (Arduino library for controlling single-wire-based LED pixels and strip) #include <stdint.h> // For uint32_t
// https://github.com/adafruit/Adafruit_NeoPixel
// Documentation : http://adafruit.github.io/Adafruit_NeoPixel/html/class_adafruit___neo_pixel.html
#include "src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h"
namespace color { namespace color {
const uint32_t red = 0xFF0000; const uint32_t red = 0xFF0000;
......
#include "lorawan.h" #include "lorawan.h"
#if defined(AMPEL_LORAWAN) && defined(ESP32) #if defined(AMPEL_LORAWAN) && defined(ESP32)
#include "led_effects.h"
#include "sensor_console.h"
#include "util.h"
#include "ntp.h"
/*** Define region and transceiver type, and ignore lmic_project_config.h from lmic library ***/
// Those values are probably okay if you're in Europe.
#define ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS
#define CFG_eu868 1
#define CFG_sx1276_radio 1
/****************************************************************************************/
// Requires "MCCI LoRaWAN LMIC library", which will be automatically used with PlatformIO but should be added in "Arduino IDE"
// Tested successfully with v3.2.0 and connected to a thethingsnetwork.org app.
#include <lmic.h>
#include <SPI.h>
#include <hal/hal.h>
#include <arduino_lmic_hal_boards.h>
namespace config { namespace config {
#if defined(CFG_eu868)
const char *lorawan_frequency_plan = "Europe 868";
#elif defined(CFG_us915)
const char *lorawan_frequency_plan = "US 915";
#elif defined(CFG_au915)
const char *lorawan_frequency_plan = "Australia 915";
#elif defined(CFG_as923)
const char *lorawan_frequency_plan = "Asia 923";
#elif defined(CFG_kr920)
const char *lorawan_frequency_plan = "Korea 920";
#elif defined(CFG_in866)
const char *lorawan_frequency_plan = "India 866";
#else
# error "Region should be specified"
#endif
// Values should be defined in config.h // Values should be defined in config.h
uint16_t lorawan_sending_interval = LORAWAN_SENDING_INTERVAL; // [s] uint16_t lorawan_sending_interval = LORAWAN_SENDING_INTERVAL; // [s]
...@@ -36,7 +71,9 @@ namespace lorawan { ...@@ -36,7 +71,9 @@ namespace lorawan {
char last_transmission[23] = ""; char last_transmission[23] = "";
void initialize() { void initialize() {
Serial.println(F("Starting LoRaWAN. Frequency plan : " LMIC_FREQUENCY_PLAN " MHz.")); Serial.print(F("Starting LoRaWAN. Frequency plan : "));
Serial.print(config::lorawan_frequency_plan);
Serial.println(F(" MHz."));
// More info about pin mapping : https://github.com/mcci-catena/arduino-lmic#pin-mapping // More info about pin mapping : https://github.com/mcci-catena/arduino-lmic#pin-mapping
// Has been tested successfully with ESP32 TTGO LoRa32 V1, and might work with other ESP32+LoRa boards. // Has been tested successfully with ESP32 TTGO LoRa32 V1, and might work with other ESP32+LoRa boards.
...@@ -51,7 +88,7 @@ namespace lorawan { ...@@ -51,7 +88,7 @@ namespace lorawan {
} }
// Checks if OTAA is connected, or if payload should be sent. // Checks if OTAA is connected, or if payload should be sent.
// NOTE: while a transaction is in process (i.e. until the TXcomplete event has been received, no blocking code (e.g. delay loops etc.) are allowed, otherwise the LMIC/OS code might miss the event. // NOTE: while a transaction is in process (i.e. until the TXcomplete event has been received), no blocking code (e.g. delay loops etc.) are allowed, otherwise the LMIC/OS code might miss the event.
// If this rule is not followed, a typical symptom is that the first send is ok and all following ones end with the 'TX not complete' failure. // If this rule is not followed, a typical symptom is that the first send is ok and all following ones end with the 'TX not complete' failure.
void process() { void process() {
os_runloop_once(); os_runloop_once();
......
...@@ -3,39 +3,15 @@ ...@@ -3,39 +3,15 @@
#include "config.h" #include "config.h"
#if defined(AMPEL_LORAWAN) && defined(ESP32) # if defined(AMPEL_LORAWAN) && defined(ESP32)
#include <Arduino.h>
// Requires "MCCI LoRaWAN LMIC library", which will be automatically used with PlatformIO but should be added in "Arduino IDE".
// Tested successfully with v3.2.0 and connected to a thethingsnetwork.org app.
#include <lmic.h>
#include <hal/hal.h>
#include <arduino_lmic_hal_boards.h>
#include <SPI.h>
#include "led_effects.h" #include <stdint.h> // For uint32_t & uint16_t
#include "sensor_console.h"
#include "util.h"
namespace config { namespace config {
extern uint16_t lorawan_sending_interval; // [s] extern uint16_t lorawan_sending_interval; // [s]
extern const char *lorawan_frequency_plan; // e.g. "Europe 868"
} }
#if defined(CFG_eu868)
# define LMIC_FREQUENCY_PLAN "Europe 868"
#elif defined(CFG_us915)
# define LMIC_FREQUENCY_PLAN "US 915"
#elif defined(CFG_au915)
# define LMIC_FREQUENCY_PLAN "Australia 915"
#elif defined(CFG_as923)
# define LMIC_FREQUENCY_PLAN "Asia 923"
#elif defined(CFG_kr920)
# define LMIC_FREQUENCY_PLAN "Korea 920"
#elif defined(CFG_in866)
# define LMIC_FREQUENCY_PLAN "India 866"
#else
# error "Region should be specified"
#endif
namespace lorawan { namespace lorawan {
extern bool waiting_for_confirmation; extern bool waiting_for_confirmation;
extern bool connected; extern bool connected;
...@@ -47,5 +23,5 @@ namespace lorawan { ...@@ -47,5 +23,5 @@ namespace lorawan {
void setLoRaInterval(int32_t sending_interval); void setLoRaInterval(int32_t sending_interval);
} }
#endif # endif
#endif #endif
#include "mqtt.h" #include "mqtt.h"
#include "config.h"
#include "led_effects.h"
#include "sensor_console.h"
#include "wifi_util.h"
#include "ntp.h"
#include "src/lib/PubSubClient/src/PubSubClient.h"
#if defined(ESP8266)
# include <ESP8266WiFi.h>
#elif defined(ESP32)
# include <WiFi.h>
#endif
namespace config { namespace config {
// Values should be defined in config.h // Values should be defined in config.h
uint16_t mqtt_sending_interval = MQTT_SENDING_INTERVAL; // [s] uint16_t mqtt_sending_interval = MQTT_SENDING_INTERVAL; // [s]
......
#ifndef MQTT_H_INCLUDED #ifndef MQTT_H_INCLUDED
#define MQTT_H_INCLUDED #define MQTT_H_INCLUDED
#include <Arduino.h> #include <stdint.h> // For uint32_t & uint16_t
#include "config.h"
#include "led_effects.h"
#include "sensor_console.h"
#include "src/lib/PubSubClient/src/PubSubClient.h"
#include "wifi_util.h"
#include "config.h"
#if !defined(MQTT_ENCRYPTED) #if !defined(MQTT_ENCRYPTED)
# define MQTT_ENCRYPTED true // Old config files might not define it, and encryption was on by default. # define MQTT_ENCRYPTED true // Old config files might not define it, and encryption was on by default.
#endif #endif
......
#include "ntp.h"
#include "sensor_console.h"
#include "config.h"
#include <WiFiUdp.h> // required for NTP
#include "src/lib/NTPClient-master/NTPClient.h" // NTP
namespace config {
const char *ntp_server = NTP_SERVER;
const long utc_offset_in_seconds = UTC_OFFSET_IN_SECONDS; // UTC+1
}
//NOTE: ESP32 sometimes couldn't access the NTP server, and every loop would take +1000ms
// ifdefs could be used to define functions specific to ESP32, e.g. with configTime
namespace ntp {
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, config::ntp_server, config::utc_offset_in_seconds, 60000UL);
bool connected_at_least_once = false;
void setLocalTime(int32_t unix_seconds);
void initialize() {
timeClient.begin();
sensor_console::defineIntCommand("set_time", ntp::setLocalTime, F("1618829570 (Sets time to the given UNIX time)"));
}
void update() {
connected_at_least_once |= timeClient.update();
}
void getLocalTime(char *timestamp) {
timeClient.getFormattedDate(timestamp);
}
void setLocalTime(int32_t unix_seconds) {
char time[23];
timeClient.getFormattedDate(time);
Serial.print(F("Current time : "));
Serial.println(time);
if (connected_at_least_once) {
Serial.println(F("NTP update already happened. Not changing anything."));
return;
}
Serial.print(F("Setting UNIX time to : "));
Serial.println(unix_seconds);
timeClient.setEpochTime(unix_seconds - seconds());
timeClient.getFormattedDate(time);
Serial.print(F("Current time : "));
Serial.println(time);
}
}
#ifndef AMPEL_TIME_H_INCLUDED
#define AMPEL_TIME_H_INCLUDED
namespace ntp {
void initialize();
void update();
void getLocalTime(char *timestamp);
}
//NOTE: Only use seconds() for duration comparison, not timestamps comparison. Otherwise, problems happen when millis roll over.
#define seconds() (millis() / 1000UL)
#endif
#ifndef SENSOR_CONSOLE_H_INCLUDED #ifndef SENSOR_CONSOLE_H_INCLUDED
#define SENSOR_CONSOLE_H_INCLUDED #define SENSOR_CONSOLE_H_INCLUDED
#include <Arduino.h> #include <Arduino.h> // For Flash strings, uint8_t and int32_t
/** Other scripts can use this namespace, in order to define commands, via callbacks. /** Other scripts can use this namespace, in order to define commands, via callbacks.
* Those callbacks can then be used to send commands to the sensor (reset, calibrate, led on/off, ...) * Those callbacks can then be used to send commands to the sensor (reset, calibrate, led on/off, ...)
...@@ -12,7 +12,7 @@ namespace sensor_console { ...@@ -12,7 +12,7 @@ namespace sensor_console {
void defineIntCommand(const char *name, void (*function)(int32_t), const __FlashStringHelper *doc_fstring); void defineIntCommand(const char *name, void (*function)(int32_t), const __FlashStringHelper *doc_fstring);
void defineStringCommand(const char *name, void (*function)(char*), const __FlashStringHelper *doc_fstring); void defineStringCommand(const char *name, void (*function)(char*), const __FlashStringHelper *doc_fstring);
void processSerialInput(const byte in_byte); void processSerialInput(const uint8_t in_byte);
void execute(const char *command_line); void execute(const char *command_line);
} }
......
#include "util.h" #include "util.h"
#include "sensor_console.h"
namespace config {
const char *ntp_server = NTP_SERVER;
const long utc_offset_in_seconds = UTC_OFFSET_IN_SECONDS; // UTC+1
}
#if defined(ESP8266) #if defined(ESP8266)
# include <ESP8266WiFi.h> // required to get MAC address
const char *current_board = "ESP8266"; const char *current_board = "ESP8266";
# if !defined(AMPEL_WIFI)
void preinit() {
// WiFi would be initialized otherwise (on ESP8266), even if unused.
// see https://github.com/esp8266/Arduino/issues/2111#issuecomment-224251391
ESP8266WiFiClass::preinitWiFiOff();
}
# endif
#elif defined(ESP32) #elif defined(ESP32)
# include <WiFi.h> // required to get MAC address
const char *current_board = "ESP32"; const char *current_board = "ESP32";
#else #else
const char *current_board = "UNKNOWN"; const char *current_board = "UNKNOWN";
#endif #endif
//NOTE: ESP32 sometimes couldn't access the NTP server, and every loop would take +1000ms
// ifdefs could be used to define functions specific to ESP32, e.g. with configTime
namespace ntp {
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, config::ntp_server, config::utc_offset_in_seconds, 60000UL);
bool connected_at_least_once = false;
void initialize() {
timeClient.begin();
}
void update() {
connected_at_least_once |= timeClient.update();
}
void getLocalTime(char *timestamp) {
timeClient.getFormattedDate(timestamp);
}
void setLocalTime(int32_t unix_seconds) {
char time[23];
timeClient.getFormattedDate(time);
Serial.print(F("Current time : "));
Serial.println(time);
if (connected_at_least_once) {
Serial.println(F("NTP update already happened. Not changing anything."));
return;
}
Serial.print(F("Setting UNIX time to : "));
Serial.println(unix_seconds);
timeClient.setEpochTime(unix_seconds - seconds());
timeClient.getFormattedDate(time);
Serial.print(F("Current time : "));
Serial.println(time);
}
}
void Ampel::showFreeSpace() { void Ampel::showFreeSpace() {
Serial.print(F("Free heap space : ")); Serial.print(F("Free heap space : "));
Serial.print(ESP.getFreeHeap()); Serial.print(ESP.getFreeHeap());
...@@ -90,7 +44,6 @@ char* getSensorId() { ...@@ -90,7 +44,6 @@ char* getSensorId() {
Ampel::Ampel() : Ampel::Ampel() :
board(current_board), sensorId(getSensorId()), macAddress(getMacString()), max_loop_duration(0) { board(current_board), sensorId(getSensorId()), macAddress(getMacString()), max_loop_duration(0) {
sensor_console::defineIntCommand("set_time", ntp::setLocalTime, F("1618829570 (Sets time to the given UNIX time)"));
sensor_console::defineCommand("free", Ampel::showFreeSpace, F("(Displays available heap space)")); sensor_console::defineCommand("free", Ampel::showFreeSpace, F("(Displays available heap space)"));
sensor_console::defineCommand("reset", []() { sensor_console::defineCommand("reset", []() {
ESP.restart(); ESP.restart();
......
#ifndef AMPEL_UTIL_H_INCLUDED #ifndef AMPEL_UTIL_H_INCLUDED
#define AMPEL_UTIL_H_INCLUDED #define AMPEL_UTIL_H_INCLUDED
#include <Arduino.h>
#include "config.h"
#include "sensor_console.h"
#include <WiFiUdp.h> // required for NTP #include <stdint.h> // For uint32_t
#include "src/lib/NTPClient-master/NTPClient.h" // NTP
#if defined(ESP8266) #if defined(ESP8266)
# include <ESP8266WiFi.h> // required to get MAC address
# define esp_get_max_free_block_size() ESP.getMaxFreeBlockSize() # define esp_get_max_free_block_size() ESP.getMaxFreeBlockSize()
# define esp_get_heap_fragmentation() ESP.getHeapFragmentation() # define esp_get_heap_fragmentation() ESP.getHeapFragmentation()
#elif defined(ESP32) #elif defined(ESP32)
# include <WiFi.h> // required to get MAC address
# define esp_get_max_free_block_size() ESP.getMaxAllocHeap() //largest block of heap that can be allocated. # define esp_get_max_free_block_size() ESP.getMaxAllocHeap() //largest block of heap that can be allocated.
# define esp_get_heap_fragmentation() "?" // apparently not available for ESP32 # define esp_get_heap_fragmentation() "?" // apparently not available for ESP32
#endif #endif
namespace ntp {
void initialize();
void update();
void getLocalTime(char *timestamp);
}
namespace util { namespace util {
template<typename Tpa, typename Tpb> template<typename Tpa, typename Tpb>
inline auto min(const Tpa &a, const Tpb &b) -> decltype(a < b ? a : b) { inline auto min(const Tpa &a, const Tpb &b) -> decltype(a < b ? a : b) {
...@@ -48,7 +36,4 @@ public: ...@@ -48,7 +36,4 @@ public:
extern Ampel ampel; extern Ampel ampel;
//NOTE: Only use seconds() for duration comparison, not timestamps comparison. Otherwise, problems happen when millis roll over.
#define seconds() (millis() / 1000UL)
#endif #endif
#include "web_server.h" #include "web_server.h"
#if defined(ESP8266)
# include <ESP8266WebServer.h>
#elif defined(ESP32)
# include <WebServer.h>
#endif
#include "config.h"
#include "util.h"
#include "ntp.h"
#include "wifi_util.h"
#include "co2_sensor.h"
#include "sensor_console.h"
#ifdef AMPEL_CSV
# include "csv_writer.h"
#endif
#ifdef AMPEL_MQTT
# include "mqtt.h"
#endif
#ifdef AMPEL_LORAWAN
# include "lorawan.h"
#endif
namespace config { namespace config {
// Values should be defined in config.h // Values should be defined in config.h
#ifdef HTTP_USER #ifdef HTTP_USER
...@@ -236,7 +258,7 @@ namespace web_server { ...@@ -236,7 +258,7 @@ namespace web_server {
mqtt::connected ? "Yes" : "No", mqtt::last_successful_publish, config::mqtt_sending_interval, mqtt::connected ? "Yes" : "No", mqtt::last_successful_publish, config::mqtt_sending_interval,
#endif #endif
#if defined(AMPEL_LORAWAN) && defined(ESP32) #if defined(AMPEL_LORAWAN) && defined(ESP32)
lorawan::connected ? "Yes" : "No", LMIC_FREQUENCY_PLAN, lorawan::last_transmission, lorawan::connected ? "Yes" : "No", config::lorawan_frequency_plan, lorawan::last_transmission,
config::lorawan_sending_interval, config::lorawan_sending_interval,
#endif #endif
config::temperature_offset, config::auto_calibrate_sensor ? "Yes" : "No", ampel.sensorId, ampel.sensorId, config::temperature_offset, config::auto_calibrate_sensor ? "Yes" : "No", ampel.sensorId, ampel.sensorId,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment