main.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include "SensorMesh.h"
  2. #ifdef DISPLAY_CLASS
  3. #include "UITask.h"
  4. static UITask ui_task(display);
  5. #endif
  6. class MyMesh : public SensorMesh {
  7. public:
  8. MyMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
  9. : SensorMesh(board, radio, ms, rng, rtc, tables),
  10. battery_data(12*24, 5*60) // 24 hours worth of battery data, every 5 minutes
  11. {
  12. }
  13. protected:
  14. /* ========================== custom logic here ========================== */
  15. Trigger low_batt, critical_batt;
  16. TimeSeriesData battery_data;
  17. void onSensorDataRead() override {
  18. float batt_voltage = getVoltage(TELEM_CHANNEL_SELF);
  19. battery_data.recordData(getRTCClock(), batt_voltage); // record battery
  20. alertIf(batt_voltage < 3.4f, critical_batt, HIGH_PRI_ALERT, "Battery is critical!");
  21. alertIf(batt_voltage < 3.6f, low_batt, LOW_PRI_ALERT, "Battery is low");
  22. }
  23. int querySeriesData(uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg dest[], int max_num) override {
  24. battery_data.calcMinMaxAvg(getRTCClock(), start_secs_ago, end_secs_ago, &dest[0], TELEM_CHANNEL_SELF, LPP_VOLTAGE);
  25. return 1;
  26. }
  27. bool handleCustomCommand(uint32_t sender_timestamp, char* command, char* reply) override {
  28. if (strcmp(command, "magic") == 0) { // example 'custom' command handling
  29. strcpy(reply, "**Magic now done**");
  30. return true; // handled
  31. }
  32. return false; // not handled
  33. }
  34. /* ======================================================================= */
  35. };
  36. StdRNG fast_rng;
  37. SimpleMeshTables tables;
  38. MyMesh the_mesh(board, radio_driver, *new ArduinoMillis(), fast_rng, rtc_clock, tables);
  39. void halt() {
  40. while (1) ;
  41. }
  42. static char command[160];
  43. void setup() {
  44. Serial.begin(115200);
  45. delay(1000);
  46. board.begin();
  47. #ifdef DISPLAY_CLASS
  48. if (display.begin()) {
  49. display.startFrame();
  50. display.print("Please wait...");
  51. display.endFrame();
  52. }
  53. #endif
  54. if (!radio_init()) { halt(); }
  55. fast_rng.begin(radio_driver.getRngSeed());
  56. FILESYSTEM* fs;
  57. #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
  58. InternalFS.begin();
  59. fs = &InternalFS;
  60. IdentityStore store(InternalFS, "");
  61. #elif defined(ESP32)
  62. SPIFFS.begin(true);
  63. fs = &SPIFFS;
  64. IdentityStore store(SPIFFS, "/identity");
  65. #elif defined(RP2040_PLATFORM)
  66. LittleFS.begin();
  67. fs = &LittleFS;
  68. IdentityStore store(LittleFS, "/identity");
  69. store.begin();
  70. #else
  71. #error "need to define filesystem"
  72. #endif
  73. if (!store.load("_main", the_mesh.self_id)) {
  74. MESH_DEBUG_PRINTLN("Generating new keypair");
  75. the_mesh.self_id = radio_new_identity(); // create new random identity
  76. int count = 0;
  77. while (count < 10 && (the_mesh.self_id.pub_key[0] == 0x00 || the_mesh.self_id.pub_key[0] == 0xFF)) { // reserved id hashes
  78. the_mesh.self_id = radio_new_identity(); count++;
  79. }
  80. store.save("_main", the_mesh.self_id);
  81. }
  82. Serial.print("Sensor ID: ");
  83. mesh::Utils::printHex(Serial, the_mesh.self_id.pub_key, PUB_KEY_SIZE); Serial.println();
  84. command[0] = 0;
  85. sensors.begin();
  86. the_mesh.begin(fs);
  87. #ifdef DISPLAY_CLASS
  88. ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
  89. #endif
  90. // send out initial zero hop Advertisement to the mesh
  91. #if ENABLE_ADVERT_ON_BOOT == 1
  92. the_mesh.sendSelfAdvertisement(16000, false);
  93. #endif
  94. }
  95. void loop() {
  96. int len = strlen(command);
  97. while (Serial.available() && len < sizeof(command)-1) {
  98. char c = Serial.read();
  99. if (c != '\n') {
  100. command[len++] = c;
  101. command[len] = 0;
  102. }
  103. Serial.print(c);
  104. }
  105. if (len == sizeof(command)-1) { // command buffer full
  106. command[sizeof(command)-1] = '\r';
  107. }
  108. if (len > 0 && command[len - 1] == '\r') { // received complete line
  109. command[len - 1] = 0; // replace newline with C string null terminator
  110. char reply[160];
  111. the_mesh.handleCommand(0, command, reply); // NOTE: there is no sender_timestamp via serial!
  112. if (reply[0]) {
  113. Serial.print(" -> "); Serial.println(reply);
  114. }
  115. command[0] = 0; // reset command buffer
  116. }
  117. the_mesh.loop();
  118. sensors.loop();
  119. #ifdef DISPLAY_CLASS
  120. ui_task.loop();
  121. #endif
  122. rtc_clock.tick();
  123. }