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 @@
#endif
#include "util.h"
#include "ntp.h"
#include "sensor_console.h"
#include "co2_sensor.h"
#include "led_effects.h"
......
......@@ -88,10 +88,7 @@ void setup() {
#ifdef AMPEL_WIFI
wifi::connect(ampel.sensorId);
Serial.print(F("WiFi - Status: "));
Serial.println(WiFi.status());
if (WiFi.status() == WL_CONNECTED) {
if (wifi::connected()) {
# ifdef AMPEL_HTTP
web_server::initialize();
# endif
......@@ -203,7 +200,7 @@ void checkFlashButton() {
void keepServicesAlive() {
#ifdef AMPEL_WIFI
if (WiFi.status() == WL_CONNECTED) {
if (wifi::connected()) {
# if defined(ESP8266)
//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.
......
#include "co2_sensor.h"
#include "config.h"
#include "ntp.h"
#include "led_effects.h"
#include "sensor_console.h"
#include <Wire.h>
namespace config {
// UPPERCASE values should be defined in config.h
uint16_t measurement_timestep = MEASUREMENT_TIMESTEP; // [s] Value between 2 and 1800 (range for SCD30 sensor).
......
......@@ -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%).
// 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 "config.h"
#include "led_effects.h"
#include "util.h"
#include "sensor_console.h"
#include <Wire.h>
namespace config {
extern uint16_t measurement_timestep; // [s] Value between 2 and 1800 (range for SCD30 sensor)
......
......@@ -119,10 +119,7 @@
*/
// 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:
// * 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
// 2) If you need to, region and transceiver type can be specified in lorawan.cpp. Default is "Europe 868"
// 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,
// e.g. on https://www.thethingsnetwork.org/docs/applications/
......
#include "csv_writer.h"
#include "config.h"
#include "ntp.h"
#include "led_effects.h"
#include "sensor_console.h"
namespace config {
// Values should be defined in config.h
uint16_t csv_interval = CSV_INTERVAL; // [s]
......
......@@ -11,11 +11,6 @@
# error Board should be either ESP8266 or ESP832
#endif
#include "config.h"
#include "util.h"
#include "led_effects.h"
#include "sensor_console.h"
namespace config {
extern uint16_t csv_interval; // [s]
}
......
#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 *
*****************************************************************/
......
#ifndef 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)
// 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"
#include <stdint.h> // For uint32_t
namespace color {
const uint32_t red = 0xFF0000;
......
#include "lorawan.h"
#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 {
#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
uint16_t lorawan_sending_interval = LORAWAN_SENDING_INTERVAL; // [s]
......@@ -36,7 +71,9 @@ namespace lorawan {
char last_transmission[23] = "";
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
// Has been tested successfully with ESP32 TTGO LoRa32 V1, and might work with other ESP32+LoRa boards.
......@@ -51,7 +88,7 @@ namespace lorawan {
}
// 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.
void process() {
os_runloop_once();
......
......@@ -3,39 +3,15 @@
#include "config.h"
#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>
# if defined(AMPEL_LORAWAN) && defined(ESP32)
#include "led_effects.h"
#include "sensor_console.h"
#include "util.h"
#include <stdint.h> // For uint32_t & uint16_t
namespace config {
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 {
extern bool waiting_for_confirmation;
extern bool connected;
......@@ -47,5 +23,5 @@ namespace lorawan {
void setLoRaInterval(int32_t sending_interval);
}
#endif
# endif
#endif
#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 {
// Values should be defined in config.h
uint16_t mqtt_sending_interval = MQTT_SENDING_INTERVAL; // [s]
......
#ifndef MQTT_H_INCLUDED
#define MQTT_H_INCLUDED
#include <Arduino.h>
#include "config.h"
#include "led_effects.h"
#include "sensor_console.h"
#include "src/lib/PubSubClient/src/PubSubClient.h"
#include "wifi_util.h"
#include <stdint.h> // For uint32_t & uint16_t
#include "config.h"
#if !defined(MQTT_ENCRYPTED)
# define MQTT_ENCRYPTED true // Old config files might not define it, and encryption was on by default.
#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
#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.
* Those callbacks can then be used to send commands to the sensor (reset, calibrate, led on/off, ...)
......@@ -12,7 +12,7 @@ namespace sensor_console {
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 processSerialInput(const byte in_byte);
void processSerialInput(const uint8_t in_byte);
void execute(const char *command_line);
}
......
#include "util.h"
namespace config {
const char *ntp_server = NTP_SERVER;
const long utc_offset_in_seconds = UTC_OFFSET_IN_SECONDS; // UTC+1
}
#include "sensor_console.h"
#if defined(ESP8266)
# include <ESP8266WiFi.h> // required to get MAC address
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)
# include <WiFi.h> // required to get MAC address
const char *current_board = "ESP32";
#else
const char *current_board = "UNKNOWN";
#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() {
Serial.print(F("Free heap space : "));
Serial.print(ESP.getFreeHeap());
......@@ -90,7 +44,6 @@ char* getSensorId() {
Ampel::Ampel() :
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("reset", []() {
ESP.restart();
......
#ifndef 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 "src/lib/NTPClient-master/NTPClient.h" // NTP
#include <stdint.h> // For uint32_t
#if defined(ESP8266)
# include <ESP8266WiFi.h> // required to get MAC address
# define esp_get_max_free_block_size() ESP.getMaxFreeBlockSize()
# define esp_get_heap_fragmentation() ESP.getHeapFragmentation()
#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_heap_fragmentation() "?" // apparently not available for ESP32
#endif
namespace ntp {
void initialize();
void update();
void getLocalTime(char *timestamp);
}
namespace util {
template<typename Tpa, typename Tpb>
inline auto min(const Tpa &a, const Tpb &b) -> decltype(a < b ? a : b) {
......@@ -48,7 +36,4 @@ public:
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
#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 {
// Values should be defined in config.h
#ifdef HTTP_USER
......@@ -236,7 +258,7 @@ namespace web_server {
mqtt::connected ? "Yes" : "No", mqtt::last_successful_publish, config::mqtt_sending_interval,
#endif
#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,
#endif
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