diff --git a/client/client_central_mast/src/main.cpp b/client/client_central_mast/src/main.cpp index c1cdd98da0cee65b8520472999c78d70ec7d442a..83c0d9a608968025fb2b6e0cc343703ed29933c6 100644 --- a/client/client_central_mast/src/main.cpp +++ b/client/client_central_mast/src/main.cpp @@ -1,134 +1,118 @@ #include "Arduino.h" #include "ESPNow.hpp" #include "NoDataAvailableException.hpp" +#include "SentecRainGaugeSensor.h" #include "rs485.hpp" -#include <list> #include <ina219.hpp> static const char *TAG = "MAIN"; #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; ForteINA219 ina219; +SEM404 rainGaugeSensor = SEM404(2, 19); float getBatteryVoltage() { - //************ Measuring Battery Voltage *********** - // reference voltage of microcontroller 3.3v for esp32 - const float reference_vcc = 3.3; - // value of R2 resistor [kOhm] - const float bat_res_gnd = 20; - // value of R1 resistor [kOhm] - const float bat_res_vcc = 68; - // max ADC value - const int adc = 4095; - float sample = 0; - // Get 100 analog read to prevent unusefully read - for (int i = 0; i < 100; i++) { - sample = - sample + analogRead(35); // read the voltage from the divider circuit - 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()); + //************ Measuring Battery Voltage *********** + // reference voltage of microcontroller 3.3v for esp32 + const float reference_vcc = 3.3; + // value of R2 resistor [kOhm] + const float bat_res_gnd = 20; + // value of R1 resistor [kOhm] + const float bat_res_vcc = 68; + // max ADC value + const int adc = 4095; + float sample = 0; + // Get 100 analog read to prevent unusefully read + for (int i = 0; i < 100; i++) { + sample = sample + analogRead(35); // read the voltage from the divider circuit + delay(2); } - 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); - } + 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; } void setup() { - // whole loop should be around ~3000 ms - Serial.begin(115200); - rs485.setup(); - - getBatteryVoltage(); - - - ina219.setup(); - ina219.setPinSetup({21, 22}); - - // ~2100ms - try { - auto messages = rs485.buildMessages(); - // split into arrays of 6 messages TODO: Make this cleaner with default constructor - std::array<Message, 6> messages_1 = - {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), - Message::nullMessage(), Message::nullMessage(), - Message::nullMessage()}; - std::array<Message, 6> messages_2 = - {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), - Message::nullMessage(), Message::nullMessage(), - Message::nullMessage()}; - - auto ina219_messages = ina219.buildMessages(); - - std::array<Message, 6> ina_array = - {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), - Message::nullMessage(), Message::nullMessage(), - Message::nullMessage()}; - - // log ina messages - for (const auto &msg: ina219_messages) { - ESP_LOGI(TAG, - "INA219 Message: %s", - msg.getMessageAsMinifiedJsonString().c_str()); - } - - - int i = 0; - for (const auto &msg: messages) { - if (i < 6) { - messages_1[i] = msg; - } else { - messages_2[i - 6] = msg; - } - i++; + // whole loop should be around ~3000 ms + Serial.begin(115200); + rs485.setup(); + + getBatteryVoltage(); + + ina219.setPinSetup({21, 22}); + ina219.setup(); + + try { + Forte_RS485::powerOnRS485Sensors(); + auto messages = rainGaugeSensor.buildMessages(); + Forte_RS485::powerOffRS485Sensors(); + // split into arrays of 6 messages TODO: Make this cleaner with default constructor + std::array<Message, 6> messages_1 = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), + Message::nullMessage(), Message::nullMessage(), Message::nullMessage()}; + + auto ina219_messages = ina219.buildMessages(); + + std::array<Message, 6> ina_array = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), + Message::nullMessage(), Message::nullMessage(), Message::nullMessage()}; + + // log ina messages + for (const auto &msg : ina219_messages) { + ESP_LOGI(TAG, "INA219 Message: %s", msg.getMessageAsMinifiedJsonString().c_str()); + } + + int i = 0; + for (const auto &msg : messages) { + if (i < 6) { + messages_1[i] = msg; + } + i++; + } + + espnow_setup(); + + // demo of how to reset the rain gauge +#ifdef RESET_RAIN_GAUGE + if (messages_1.front().getClientDataPackage().getMeasurementData().getValue() > 20) { + Forte_RS485::powerOnRS485Sensors(); + if (rainGaugeSensor.resetPrecipitation() == ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION) { + ESP_LOGE(TAG, "Could not reset precipitation"); + auto precipitationErrorMessage = Message( + Measurement(ERROR_VALUE, rainGaugeSensor.address, NO_I2C_ADDRESS, MeasurementType::PRECIPITATION, + 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; - 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'; - } + rs485.teardown(); - 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_deep_sleep_start(); + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + esp_deep_sleep_start(); } void loop() {} diff --git a/client/client_satellite/src/main.cpp b/client/client_satellite/src/main.cpp index 7f729b96215a8e83b8860a8b902c071aac17f50f..aca2470dfce090b1497522451127a5c3dba61cdd 100644 --- a/client/client_satellite/src/main.cpp +++ b/client/client_satellite/src/main.cpp @@ -4,14 +4,16 @@ #include "dr26.hpp" #include "f_deep_sleep.hpp" #include <Arduino.h> +#include <SentecRainGaugeSensor.h> #include <list> +#include <rs485.hpp> // Execution time: // FIXME: Boot: needs to be optimised. should be around 300 ms, can be <100ms // https://github.com/makermoekoe/Picoclick-C3#speed-up-boot-process // Part [ms] // Boot: 300 -// First setup: 150 +// First setup: 150 // Data aquisition: 500 (4 Dendrometers) // ESPNow setup: 220 // Sending 580 @@ -26,105 +28,118 @@ static const char *TAG = "MAIN"; 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_channel3; ForteDR26 dr26_channel1; 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 -void setup() -{ - unsigned long ts = millis(); - Serial.begin(115200); - // Set the GPIO which conrtols the step up to OUTPUT - gpio_set_direction(GPIO_NUM_32, GPIO_MODE_OUTPUT); - - // blinking led for debug - // gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); - // gpio_set_level(GPIO_NUM_17, 1); - - battery_monitor.begin(); - - DeepSleep::print_wakeup_reason(); - 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 - if (battery_monitor.cellVoltage_mV() < 3200) { - battery_monitor.setPowerMode(LC709203F_POWER_SLEEP); - esp_deep_sleep_start(); - } - - gpio_set_level(GPIO_NUM_32, 1); - // delay(100); - dr26_channel1.setup(); - dr26_channel0.setChannel(0); - dr26_channel1.setChannel(1); - dr26_channel2.setChannel(2); - dr26_channel3.setChannel(3); - - ESP_LOGD(TAG, "Setup took %ld ms", millis() - ts); - - try { - // FIXME: put me into seperate trys? No data will be sent when 1 exception occurs - - ts = millis(); - auto messages0 = dr26_channel0.buildMessages(); - auto messages1 = dr26_channel1.buildMessages(); - auto messages2 = dr26_channel2.buildMessages(); - auto messages3 = dr26_channel3.buildMessages(); - auto messages4 = battery_monitor.buildMessages(); - // roughly takes 500ms, ~120ms for each adc channel, barely anything for battery monitor - ESP_LOGD(TAG, "Reading data and building messages took %ld ms", millis() - ts); - gpio_set_level(GPIO_NUM_32, 0); - - // FIXME: put this outside the try loop? - ts = millis(); - espnow_setup(); - ESP_LOGD(TAG, "EPSNow setup took %ld ms", millis() - ts); - ts = millis(); - send_msgs(messages0); - send_msgs(messages1); - send_msgs(messages2); - send_msgs(messages3); - send_msgs(messages4); - // 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(10 * 60); - } else { - esp_deep_sleep_start(); - } +void setup() { + unsigned long ts = millis(); + Serial.begin(115200); + rs485.setup(); + // Set the GPIO which conrtols the step up to OUTPUT + gpio_set_direction(GPIO_NUM_32, GPIO_MODE_OUTPUT); + + // blinking led for debug + // gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); + // gpio_set_level(GPIO_NUM_17, 1); + + battery_monitor.begin(); + + DeepSleep::print_wakeup_reason(); + 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 + if (battery_monitor.cellVoltage_mV() < 3200) { + battery_monitor.setPowerMode(LC709203F_POWER_SLEEP); + esp_deep_sleep_start(); + } + + gpio_set_level(GPIO_NUM_32, 1); + // delay(100); + dr26_channel1.setup(); + dr26_channel0.setChannel(0); + dr26_channel1.setChannel(1); + dr26_channel2.setChannel(2); + dr26_channel3.setChannel(3); + + ESP_LOGD(TAG, "Setup took %ld ms", millis() - ts); + + try { + // FIXME: put me into seperate trys? No data will be sent when 1 exception occurs + + ts = millis(); + // auto messages0 = dr26_channel0.buildMessages(); + // auto messages1 = dr26_channel1.buildMessages(); + // auto messages2 = dr26_channel2.buildMessages(); + // auto messages3 = dr26_channel3.buildMessages(); + // auto messages4 = battery_monitor.buildMessages(); + Forte_RS485::powerOnRS485Sensors(); + auto soilMessage = rainGaugeSensor.buildMessages(); + Forte_RS485::powerOffRS485Sensors(); + // roughly takes 500ms, ~120ms for each adc channel, barely anything for battery monitor + ESP_LOGD(TAG, "Reading data and building messages took %ld ms", millis() - ts); + gpio_set_level(GPIO_NUM_32, 0); + + // std::array<Message, 6> messages = + // {messages0.front(), messages1.front(), messages2.front(), + // messages3.front(), messages4.front(), soilMessage.front()}; + std::array<Message, 6> messages = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(), + Message::nullMessage(), Message::nullMessage(), soilMessage.front()}; + + ts = millis(); + espnow_setup(); + ESP_LOGD(TAG, "EPSNow setup took %ld ms", millis() - ts); + + if (messages.back().getClientDataPackage().getMeasurementData().getValue() > 20) { + Forte_RS485::powerOnRS485Sensors(); + if (rainGaugeSensor.resetPrecipitation() == ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION) { + ESP_LOGE(TAG, "Could not reset precipitation"); + auto precipitationErrorMessage = Message( + Measurement(ERROR_VALUE, rainGaugeSensor.address, NO_I2C_ADDRESS, MeasurementType::PRECIPITATION, + 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(); + } + + 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() {} \ No newline at end of file diff --git a/client/libs/rs485/rs485.cpp b/client/libs/rs485/rs485.cpp index b2ec8b69832b09bba69bdbb3afea1c2cf8d67042..cb108ad78c9b0c2112194b694b44d36c97f6994d 100644 --- a/client/libs/rs485/rs485.cpp +++ b/client/libs/rs485/rs485.cpp @@ -51,7 +51,7 @@ void Forte_RS485::powerOnRS485Sensors() { // Power on sensor digitalWrite(POWER_SWITCH_PIN_12V, HIGH); digitalWrite(POWER_SWITCH_PIN_5V, HIGH); // Wait for sensors to power up // TODO minimize delay - delay(2000); + delay(1000); } std::list<Message> Forte_RS485::buildMessages() {