Skip to content
Snippets Groups Projects
Verified Commit 40e67cd7 authored by Zoe Michaela Dietmar Pfister's avatar Zoe Michaela Dietmar Pfister :gay_pride_flag:
Browse files

reduce rs485 delay, add demo code of rain gauge (could also be another rs485...

reduce rs485 delay, add demo code of rain gauge (could also be another rs485 sensor) to client satellite and central mast
parent bb49b9f8
No related branches found
No related tags found
2 merge requests!39Merge Develop into Main,!30Renamed Sentec Sensors, made RS485 serial connection a singleton shared...
Pipeline #102064 passed
#include "Arduino.h" #include "Arduino.h"
#include "ESPNow.hpp" #include "ESPNow.hpp"
#include "NoDataAvailableException.hpp" #include "NoDataAvailableException.hpp"
#include "SentecRainGaugeSensor.h"
#include "rs485.hpp" #include "rs485.hpp"
#include <list>
#include <ina219.hpp> #include <ina219.hpp>
static const char *TAG = "MAIN"; static const char *TAG = "MAIN";
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */ #define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 5 * 1 /* Time ESP32 will go to sleep (in seconds) */ #define TIME_TO_SLEEP 0 * 1 /* Time ESP32 will go to sleep (in seconds) */
Forte_RS485 rs485; Forte_RS485 rs485;
ForteINA219 ina219; ForteINA219 ina219;
SEM404 rainGaugeSensor = SEM404(2, 19);
float getBatteryVoltage() { float getBatteryVoltage() {
//************ Measuring Battery Voltage *********** //************ Measuring Battery Voltage ***********
// reference voltage of microcontroller 3.3v for esp32 // reference voltage of microcontroller 3.3v for esp32
const float reference_vcc = 3.3; const float reference_vcc = 3.3;
// value of R2 resistor [kOhm] // value of R2 resistor [kOhm]
const float bat_res_gnd = 20; const float bat_res_gnd = 20;
// value of R1 resistor [kOhm] // value of R1 resistor [kOhm]
const float bat_res_vcc = 68; const float bat_res_vcc = 68;
// max ADC value // max ADC value
const int adc = 4095; const int adc = 4095;
float sample = 0; float sample = 0;
// Get 100 analog read to prevent unusefully read // Get 100 analog read to prevent unusefully read
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
sample = sample = sample + analogRead(35); // read the voltage from the divider circuit
sample + analogRead(35); // read the voltage from the divider circuit delay(2);
delay(2);
}
sample = sample / 100;
float battery_voltage =
(sample / 4095 * reference_vcc * (bat_res_vcc + bat_res_gnd)
/ bat_res_gnd);
ESP_LOGI(TAG, "Battery Voltage: %4.2f V", battery_voltage);
ESP_LOGD(TAG, "ADC mean Value: %4.2f", sample);
return battery_voltage;
}
// FIXME: put this in ESPNow.hpp and let stupid Markus Rampp know how you did it. After years of Python he moved past
// the idea of types and declarations
void send_msgs(const std::__cxx11::list<Message> msgs) {
for (const Message &msg: msgs) {
if (msg.send() != ESP_OK) {
RtcMemory::store_data(msg.getMessageAsMinifiedJsonString());
} }
unsigned long ts = millis(); sample = sample / 100;
// it takes ~110ms for receiving an acknowledgement by the host in perfect conditions float battery_voltage = (sample / 4095 * reference_vcc * (bat_res_vcc + bat_res_gnd) / bat_res_gnd);
uint16_t message_timeout = 2000; ESP_LOGI(TAG, "Battery Voltage: %4.2f V", battery_voltage);
while (!was_msg_received()) { ESP_LOGD(TAG, "ADC mean Value: %4.2f", sample);
if ((millis() - ts) > message_timeout) { return battery_voltage;
RtcMemory::store_data(msg.getMessageAsMinifiedJsonString());
ESP_LOGE(TAG, "Timeout: Host not available\n");
break;
}
}
ESP_LOGD(TAG, "Time until acknowledgement: %ld", millis() - ts);
}
} }
void setup() { void setup() {
// whole loop should be around ~3000 ms // whole loop should be around ~3000 ms
Serial.begin(115200); Serial.begin(115200);
rs485.setup(); rs485.setup();
getBatteryVoltage(); getBatteryVoltage();
ina219.setPinSetup({21, 22});
ina219.setup(); ina219.setup();
ina219.setPinSetup({21, 22});
try {
// ~2100ms Forte_RS485::powerOnRS485Sensors();
try { auto messages = rainGaugeSensor.buildMessages();
auto messages = rs485.buildMessages(); Forte_RS485::powerOffRS485Sensors();
// split into arrays of 6 messages TODO: Make this cleaner with default constructor // split into arrays of 6 messages TODO: Make this cleaner with default constructor
std::array<Message, 6> messages_1 = std::array<Message, 6> messages_1 = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
{Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), Message::nullMessage()};
Message::nullMessage(), Message::nullMessage(),
Message::nullMessage()}; auto ina219_messages = ina219.buildMessages();
std::array<Message, 6> messages_2 =
{Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), std::array<Message, 6> ina_array = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), Message::nullMessage()};
Message::nullMessage()};
// log ina messages
auto ina219_messages = ina219.buildMessages(); for (const auto &msg : ina219_messages) {
ESP_LOGI(TAG, "INA219 Message: %s", msg.getMessageAsMinifiedJsonString().c_str());
std::array<Message, 6> ina_array = }
{Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
Message::nullMessage(), Message::nullMessage(), int i = 0;
Message::nullMessage()}; for (const auto &msg : messages) {
if (i < 6) {
// log ina messages messages_1[i] = msg;
for (const auto &msg: ina219_messages) { }
ESP_LOGI(TAG, i++;
"INA219 Message: %s", }
msg.getMessageAsMinifiedJsonString().c_str());
} espnow_setup();
// demo of how to reset the rain gauge
int i = 0; #ifdef RESET_RAIN_GAUGE
for (const auto &msg: messages) { if (messages_1.front().getClientDataPackage().getMeasurementData().getValue() > 20) {
if (i < 6) { Forte_RS485::powerOnRS485Sensors();
messages_1[i] = msg; if (rainGaugeSensor.resetPrecipitation() == ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION) {
} else { ESP_LOGE(TAG, "Could not reset precipitation");
messages_2[i - 6] = msg; auto precipitationErrorMessage = Message(
} Measurement(ERROR_VALUE, rainGaugeSensor.address, NO_I2C_ADDRESS, MeasurementType::PRECIPITATION,
i++; ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION),
rainGaugeSensor.getSensorInformation(), Time::getInstance().getEpochSeconds());
std::array<Message, 6> messages_error = {precipitationErrorMessage, Message::nullMessage(),
Message::nullMessage(), Message::nullMessage(),
Message::nullMessage(), Message::nullMessage()};
Message::sendMessages(messages_error);
}
Forte_RS485::powerOffRS485Sensors();
}
#endif
i = 0;
for (const auto &msg : ina219_messages) {
ina_array[i] = msg;
i++;
}
Message::sendMessages(messages_1);
// Message::sendMessages(ina_array);
} catch (const NoDataAvailableException &e) {
std::cerr << e.what() << '\n';
} }
i = 0; rs485.teardown();
for (const auto &msg: ina219_messages) {
ina_array[i] = msg;
i++;
}
espnow_setup();
Message::sendMessages(messages_1);
Message::sendMessages(messages_2);
Message::sendMessages(ina_array);
} catch (const NoDataAvailableException &e) {
std::cerr << e.what() << '\n';
}
ESP_LOGD(TAG, "Going to sleep for %d seconds", TIME_TO_SLEEP); ESP_LOGD(TAG, "Going to sleep for %d seconds", TIME_TO_SLEEP);
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
esp_deep_sleep_start(); esp_deep_sleep_start();
} }
void loop() {} void loop() {}
...@@ -4,14 +4,16 @@ ...@@ -4,14 +4,16 @@
#include "dr26.hpp" #include "dr26.hpp"
#include "f_deep_sleep.hpp" #include "f_deep_sleep.hpp"
#include <Arduino.h> #include <Arduino.h>
#include <SentecRainGaugeSensor.h>
#include <list> #include <list>
#include <rs485.hpp>
// Execution time: // Execution time:
// FIXME: Boot: needs to be optimised. should be around 300 ms, can be <100ms // FIXME: Boot: needs to be optimised. should be around 300 ms, can be <100ms
// https://github.com/makermoekoe/Picoclick-C3#speed-up-boot-process // https://github.com/makermoekoe/Picoclick-C3#speed-up-boot-process
// Part [ms] // Part [ms]
// Boot: 300 // Boot: 300
// First setup: 150 // First setup: 150
// Data aquisition: 500 (4 Dendrometers) // Data aquisition: 500 (4 Dendrometers)
// ESPNow setup: 220 // ESPNow setup: 220
// Sending 580 // Sending 580
...@@ -26,105 +28,118 @@ static const char *TAG = "MAIN"; ...@@ -26,105 +28,118 @@ static const char *TAG = "MAIN";
LC709203F battery_monitor; LC709203F battery_monitor;
#define RS485Serial Serial2
#define RE_DE_PIN 19 // Line to pull high or low to receive or send data from RS485
#define RXPin 14 // Serial Receive pin
#define TXPin 15 // Serial Transmit pin
#define POWER_SWITCH_PIN_12V 12
#define POWER_SWITCH_PIN_5V 13
Forte_RS485 rs485;
SEM404 rainGaugeSensor{2, RE_DE_PIN};
ForteDR26 dr26_channel0; ForteDR26 dr26_channel0;
ForteDR26 dr26_channel3; ForteDR26 dr26_channel3;
ForteDR26 dr26_channel1; ForteDR26 dr26_channel1;
ForteDR26 dr26_channel2; ForteDR26 dr26_channel2;
void send_msgs(const std::__cxx11::list<Message> msgs)
{
for (const Message &msg : msgs) {
if (msg.send() != ESP_OK) {
RtcMemory::store_data(msg.getMessageAsMinifiedJsonString());
}
unsigned long ts = millis();
// it takes ~110ms for receiving an acknowledgement by the host in perfect conditions
uint16_t message_timeout = 2000;
while (!was_msg_received()) {
if ((millis() - ts) > message_timeout) {
RtcMemory::store_data(msg.getMessageAsMinifiedJsonString());
ESP_LOGE(TAG, "Timeout: Host not available\n");
break;
}
}
ESP_LOGD(TAG, "Time until acknowledgement: %ld", millis() - ts);
}
}
// one loop takes ~2200 ms // one loop takes ~2200 ms
void setup() void setup() {
{ unsigned long ts = millis();
unsigned long ts = millis(); Serial.begin(115200);
Serial.begin(115200); rs485.setup();
// Set the GPIO which conrtols the step up to OUTPUT // Set the GPIO which conrtols the step up to OUTPUT
gpio_set_direction(GPIO_NUM_32, GPIO_MODE_OUTPUT); gpio_set_direction(GPIO_NUM_32, GPIO_MODE_OUTPUT);
// blinking led for debug // blinking led for debug
// gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); // gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);
// gpio_set_level(GPIO_NUM_17, 1); // gpio_set_level(GPIO_NUM_17, 1);
battery_monitor.begin(); battery_monitor.begin();
DeepSleep::print_wakeup_reason(); DeepSleep::print_wakeup_reason();
DeepSleep::bootCount++; DeepSleep::bootCount++;
ESP_LOGD(TAG, "Boot number: %d", DeepSleep::bootCount); ESP_LOGD(TAG, "Boot number: %d", DeepSleep::bootCount);
// battery protection: go to deep sleep for unlimited time when voltage less than 3.2V // battery protection: go to deep sleep for unlimited time when voltage less than 3.2V
if (battery_monitor.cellVoltage_mV() < 3200) { if (battery_monitor.cellVoltage_mV() < 3200) {
battery_monitor.setPowerMode(LC709203F_POWER_SLEEP); battery_monitor.setPowerMode(LC709203F_POWER_SLEEP);
esp_deep_sleep_start(); esp_deep_sleep_start();
} }
gpio_set_level(GPIO_NUM_32, 1); gpio_set_level(GPIO_NUM_32, 1);
// delay(100); // delay(100);
dr26_channel1.setup(); dr26_channel1.setup();
dr26_channel0.setChannel(0); dr26_channel0.setChannel(0);
dr26_channel1.setChannel(1); dr26_channel1.setChannel(1);
dr26_channel2.setChannel(2); dr26_channel2.setChannel(2);
dr26_channel3.setChannel(3); dr26_channel3.setChannel(3);
ESP_LOGD(TAG, "Setup took %ld ms", millis() - ts); ESP_LOGD(TAG, "Setup took %ld ms", millis() - ts);
try { try {
// FIXME: put me into seperate trys? No data will be sent when 1 exception occurs // FIXME: put me into seperate trys? No data will be sent when 1 exception occurs
ts = millis(); ts = millis();
auto messages0 = dr26_channel0.buildMessages(); // auto messages0 = dr26_channel0.buildMessages();
auto messages1 = dr26_channel1.buildMessages(); // auto messages1 = dr26_channel1.buildMessages();
auto messages2 = dr26_channel2.buildMessages(); // auto messages2 = dr26_channel2.buildMessages();
auto messages3 = dr26_channel3.buildMessages(); // auto messages3 = dr26_channel3.buildMessages();
auto messages4 = battery_monitor.buildMessages(); // auto messages4 = battery_monitor.buildMessages();
// roughly takes 500ms, ~120ms for each adc channel, barely anything for battery monitor Forte_RS485::powerOnRS485Sensors();
ESP_LOGD(TAG, "Reading data and building messages took %ld ms", millis() - ts); auto soilMessage = rainGaugeSensor.buildMessages();
gpio_set_level(GPIO_NUM_32, 0); Forte_RS485::powerOffRS485Sensors();
// roughly takes 500ms, ~120ms for each adc channel, barely anything for battery monitor
// FIXME: put this outside the try loop? ESP_LOGD(TAG, "Reading data and building messages took %ld ms", millis() - ts);
ts = millis(); gpio_set_level(GPIO_NUM_32, 0);
espnow_setup();
ESP_LOGD(TAG, "EPSNow setup took %ld ms", millis() - ts); // std::array<Message, 6> messages =
ts = millis(); // {messages0.front(), messages1.front(), messages2.front(),
send_msgs(messages0); // messages3.front(), messages4.front(), soilMessage.front()};
send_msgs(messages1); std::array<Message, 6> messages = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
send_msgs(messages2); Message::nullMessage(), Message::nullMessage(), soilMessage.front()};
send_msgs(messages3);
send_msgs(messages4); ts = millis();
// roughly takes 3s in ideal conditions espnow_setup();
ESP_LOGD(TAG, "Sending messages took %ld ms", millis() - ts); ESP_LOGD(TAG, "EPSNow setup took %ld ms", millis() - ts);
} catch (const NoDataAvailableException &e) { if (messages.back().getClientDataPackage().getMeasurementData().getValue() > 20) {
std::cerr << e.what() << '\n'; Forte_RS485::powerOnRS485Sensors();
} if (rainGaugeSensor.resetPrecipitation() == ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION) {
// just to be safe in case exception happens above ESP_LOGE(TAG, "Could not reset precipitation");
gpio_set_level(GPIO_NUM_32, 0); auto precipitationErrorMessage = Message(
// keep it in deep sleep Measurement(ERROR_VALUE, rainGaugeSensor.address, NO_I2C_ADDRESS, MeasurementType::PRECIPITATION,
gpio_hold_en((gpio_num_t)GPIO_NUM_32); ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION),
rainGaugeSensor.getSensorInformation(), Time::getInstance().getEpochSeconds());
battery_monitor.setPowerMode(LC709203F_POWER_SLEEP); std::array<Message, 6> messages_error = {precipitationErrorMessage, Message::nullMessage(),
// battery protection: go to deep sleep for unlimited time when voltage less than 3.2V Message::nullMessage(), Message::nullMessage(),
if (battery_monitor.cellVoltage_mV() > 3200) { Message::nullMessage(), Message::nullMessage()};
DeepSleep::deep_sleep(10 * 60); Message::sendMessages(messages_error);
} else { }
esp_deep_sleep_start(); Forte_RS485::powerOffRS485Sensors();
} }
ts = millis();
Message::sendMessages(messages);
// roughly takes 3s in ideal conditions
ESP_LOGD(TAG, "Sending messages took %ld ms", millis() - ts);
} catch (const NoDataAvailableException &e) {
std::cerr << e.what() << '\n';
}
// just to be safe in case exception happens above
gpio_set_level(GPIO_NUM_32, 0);
// keep it in deep sleep
gpio_hold_en((gpio_num_t)GPIO_NUM_32);
battery_monitor.setPowerMode(LC709203F_POWER_SLEEP);
// battery protection: go to deep sleep for unlimited time when voltage less than 3.2V
if (battery_monitor.cellVoltage_mV() > 3200) {
DeepSleep::deep_sleep(2);
} else {
esp_deep_sleep_start();
}
} }
void loop() {} void loop() {}
\ No newline at end of file
...@@ -51,7 +51,7 @@ void Forte_RS485::powerOnRS485Sensors() { // Power on sensor ...@@ -51,7 +51,7 @@ void Forte_RS485::powerOnRS485Sensors() { // Power on sensor
digitalWrite(POWER_SWITCH_PIN_12V, HIGH); digitalWrite(POWER_SWITCH_PIN_12V, HIGH);
digitalWrite(POWER_SWITCH_PIN_5V, HIGH); // Wait for sensors to power up digitalWrite(POWER_SWITCH_PIN_5V, HIGH); // Wait for sensors to power up
// TODO minimize delay // TODO minimize delay
delay(2000); delay(1000);
} }
std::list<Message> Forte_RS485::buildMessages() { std::list<Message> Forte_RS485::buildMessages() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment