mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-28 02:32:09 +00:00
commit
0fe046b92d
@ -42,6 +42,7 @@ For an detailed walk-through aimed at beginners, we recommend [meshtastic.letsta
|
|||||||
### Related Groups
|
### Related Groups
|
||||||
|
|
||||||
Telegram group for **Italy**-based users [t.me/meshtastic_italia](http://t.me/meshtastic_italia) (Italian language, unofficial).
|
Telegram group for **Italy**-based users [t.me/meshtastic_italia](http://t.me/meshtastic_italia) (Italian language, unofficial).
|
||||||
|
Telegram group for **Russian**-based users [t.me/meshtastic_russia](https://t.me/meshtastic_russia) (Russian language, unofficial).
|
||||||
|
|
||||||
# Updates
|
# Updates
|
||||||
|
|
||||||
|
@ -104,6 +104,8 @@ build_flags =
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
${arduino_base.lib_deps}
|
${arduino_base.lib_deps}
|
||||||
https://github.com/meshtastic/esp32_https_server.git
|
https://github.com/meshtastic/esp32_https_server.git
|
||||||
|
adafruit/DHT sensor library@^1.4.1
|
||||||
|
adafruit/Adafruit Unified Sensor@^1.1.4
|
||||||
# Hmm - this doesn't work yet
|
# Hmm - this doesn't work yet
|
||||||
# board_build.ldscript = linker/esp32.extram.bss.ld
|
# board_build.ldscript = linker/esp32.extram.bss.ld
|
||||||
lib_ignore = segger_rtt
|
lib_ignore = segger_rtt
|
||||||
|
2
proto
2
proto
@ -1 +1 @@
|
|||||||
Subproject commit 0cadaed3953f66cf1edc99d0fa53e4fd5ebf56d6
|
Subproject commit d70f6f6f669df79c9423795caf34adbd28967e19
|
@ -64,6 +64,10 @@ uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
|
|||||||
// Threshold values for the GPS lock accuracy bar display
|
// Threshold values for the GPS lock accuracy bar display
|
||||||
uint32_t dopThresholds[5] = {2000, 1000, 500, 200, 100};
|
uint32_t dopThresholds[5] = {2000, 1000, 500, 200, 100};
|
||||||
|
|
||||||
|
// At some point, we're going to ask all of the plugins if they would like to display a screen frame
|
||||||
|
// we'll need to hold onto pointers for the plugins that can draw a frame.
|
||||||
|
std::vector<MeshPlugin *> pluginFrames;
|
||||||
|
|
||||||
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
||||||
static char ourId[5];
|
static char ourId[5];
|
||||||
|
|
||||||
@ -144,6 +148,30 @@ static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
|||||||
drawIconScreen("Sleeping...", display, state, x, y);
|
drawIconScreen("Sleeping...", display, state, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
|
{
|
||||||
|
uint8_t plugin_frame;
|
||||||
|
// there's a little but in the UI transition code
|
||||||
|
// where it invokes the function at the correct offset
|
||||||
|
// in the array of "drawScreen" functions; however,
|
||||||
|
// the passed-state doesn't quite reflect the "current"
|
||||||
|
// screen, so we have to detect it.
|
||||||
|
if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) {
|
||||||
|
// if we're transitioning from the end of the frame list back around to the first
|
||||||
|
// frame, then we want this to be `0`
|
||||||
|
plugin_frame = state->transitionFrameTarget;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// otherwise, just display the plugin frame that's aligned with the current frame
|
||||||
|
plugin_frame = state->currentFrame;
|
||||||
|
//DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame);
|
||||||
|
}
|
||||||
|
//DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
|
||||||
|
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
|
||||||
|
pi.drawFrame(display,state,x,y);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
@ -887,6 +915,11 @@ void Screen::setFrames()
|
|||||||
DEBUG_MSG("showing standard frames\n");
|
DEBUG_MSG("showing standard frames\n");
|
||||||
showingNormalScreen = true;
|
showingNormalScreen = true;
|
||||||
|
|
||||||
|
pluginFrames = MeshPlugin::GetMeshPluginsWithUIFrames();
|
||||||
|
DEBUG_MSG("Showing %d plugin frames\n", pluginFrames.size());
|
||||||
|
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + pluginFrames.size();
|
||||||
|
DEBUG_MSG("Total frame count: %d\n", totalFrameCount);
|
||||||
|
|
||||||
// We don't show the node info our our node (if we have it yet - we should)
|
// We don't show the node info our our node (if we have it yet - we should)
|
||||||
size_t numnodes = nodeStatus->getNumTotal();
|
size_t numnodes = nodeStatus->getNumTotal();
|
||||||
if (numnodes > 0)
|
if (numnodes > 0)
|
||||||
@ -894,6 +927,18 @@ void Screen::setFrames()
|
|||||||
|
|
||||||
size_t numframes = 0;
|
size_t numframes = 0;
|
||||||
|
|
||||||
|
// put all of the plugin frames first.
|
||||||
|
// this is a little bit of a dirty hack; since we're going to call
|
||||||
|
// the same drawPluginFrame handler here for all of these plugin frames
|
||||||
|
// and then we'll just assume that the state->currentFrame value
|
||||||
|
// is the same offset into the pluginFrames vector
|
||||||
|
// so that we can invoke the plugin's callback
|
||||||
|
for (auto i = pluginFrames.begin(); i != pluginFrames.end(); ++i) {
|
||||||
|
normalFrames[numframes++] = drawPluginFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
|
||||||
|
|
||||||
// If we have a critical fault, show it first
|
// If we have a critical fault, show it first
|
||||||
if (myNodeInfo.error_code)
|
if (myNodeInfo.error_code)
|
||||||
normalFrames[numframes++] = drawCriticalFaultFrame;
|
normalFrames[numframes++] = drawCriticalFaultFrame;
|
||||||
@ -922,6 +967,8 @@ void Screen::setFrames()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DEBUG_MSG("Finished building frames. numframes: %d\n", numframes);
|
||||||
|
|
||||||
ui.setFrames(normalFrames, numframes);
|
ui.setFrames(normalFrames, numframes);
|
||||||
ui.enableAllIndicators();
|
ui.enableAllIndicators();
|
||||||
|
|
||||||
|
@ -75,4 +75,18 @@ void MeshPlugin::sendResponse(const MeshPacket &req) {
|
|||||||
void setReplyTo(MeshPacket *p, const MeshPacket &to) {
|
void setReplyTo(MeshPacket *p, const MeshPacket &to) {
|
||||||
p->to = to.from;
|
p->to = to.from;
|
||||||
p->want_ack = to.want_ack;
|
p->want_ack = to.want_ack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames() {
|
||||||
|
|
||||||
|
std::vector<MeshPlugin *> pluginsWithUIFrames;
|
||||||
|
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
|
||||||
|
auto &pi = **i;
|
||||||
|
if ( pi.wantUIFrame()) {
|
||||||
|
DEBUG_MSG("Plugin wants a UI Frame\n");
|
||||||
|
pluginsWithUIFrames.push_back(&pi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pluginsWithUIFrames;
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "mesh/MeshTypes.h"
|
#include "mesh/MeshTypes.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <OLEDDisplay.h>
|
||||||
|
#include <OLEDDisplayUi.h>
|
||||||
/** A baseclass for any mesh "plugin".
|
/** A baseclass for any mesh "plugin".
|
||||||
*
|
*
|
||||||
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
|
||||||
@ -14,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
class MeshPlugin
|
class MeshPlugin
|
||||||
{
|
{
|
||||||
static std::vector<MeshPlugin *> *plugins;
|
static std::vector<MeshPlugin *> *plugins;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructor
|
/** Constructor
|
||||||
@ -28,6 +30,10 @@ class MeshPlugin
|
|||||||
*/
|
*/
|
||||||
static void callPlugins(const MeshPacket &mp);
|
static void callPlugins(const MeshPacket &mp);
|
||||||
|
|
||||||
|
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
|
||||||
|
|
||||||
|
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
@ -61,6 +67,13 @@ class MeshPlugin
|
|||||||
* so that subclasses can (optionally) send a response back to the original sender. */
|
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||||
virtual MeshPacket *allocReply() { return NULL; }
|
virtual MeshPacket *allocReply() { return NULL; }
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @return true if you want to be alloced a UI screen frame
|
||||||
|
*/
|
||||||
|
virtual bool wantUIFrame() { return false; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
@ -80,10 +80,10 @@ extern const pb_msgdesc_t DeviceState_msg;
|
|||||||
#define DeviceState_fields &DeviceState_msg
|
#define DeviceState_fields &DeviceState_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define DeviceState_size 6266
|
#define DeviceState_size 6293
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
12
src/mesh/generated/environmental_measurement.pb.c
Normal file
12
src/mesh/generated/environmental_measurement.pb.c
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/* Automatically generated nanopb constant definitions */
|
||||||
|
/* Generated by nanopb-0.4.4 */
|
||||||
|
|
||||||
|
#include "environmental_measurement.pb.h"
|
||||||
|
#if PB_PROTO_HEADER_VERSION != 40
|
||||||
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PB_BIND(EnvironmentalMeasurement, EnvironmentalMeasurement, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
|
53
src/mesh/generated/environmental_measurement.pb.h
Normal file
53
src/mesh/generated/environmental_measurement.pb.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/* Automatically generated nanopb header */
|
||||||
|
/* Generated by nanopb-0.4.4 */
|
||||||
|
|
||||||
|
#ifndef PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED
|
||||||
|
#define PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED
|
||||||
|
#include <pb.h>
|
||||||
|
|
||||||
|
#if PB_PROTO_HEADER_VERSION != 40
|
||||||
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Struct definitions */
|
||||||
|
typedef struct _EnvironmentalMeasurement {
|
||||||
|
float temperature;
|
||||||
|
float relative_humidity;
|
||||||
|
float barometric_pressure;
|
||||||
|
} EnvironmentalMeasurement;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Initializer values for message structs */
|
||||||
|
#define EnvironmentalMeasurement_init_default {0, 0, 0}
|
||||||
|
#define EnvironmentalMeasurement_init_zero {0, 0, 0}
|
||||||
|
|
||||||
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
|
#define EnvironmentalMeasurement_temperature_tag 1
|
||||||
|
#define EnvironmentalMeasurement_relative_humidity_tag 2
|
||||||
|
#define EnvironmentalMeasurement_barometric_pressure_tag 3
|
||||||
|
|
||||||
|
/* Struct field encoding specification for nanopb */
|
||||||
|
#define EnvironmentalMeasurement_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, FLOAT, temperature, 1) \
|
||||||
|
X(a, STATIC, SINGULAR, FLOAT, relative_humidity, 2) \
|
||||||
|
X(a, STATIC, SINGULAR, FLOAT, barometric_pressure, 3)
|
||||||
|
#define EnvironmentalMeasurement_CALLBACK NULL
|
||||||
|
#define EnvironmentalMeasurement_DEFAULT NULL
|
||||||
|
|
||||||
|
extern const pb_msgdesc_t EnvironmentalMeasurement_msg;
|
||||||
|
|
||||||
|
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||||
|
#define EnvironmentalMeasurement_fields &EnvironmentalMeasurement_msg
|
||||||
|
|
||||||
|
/* Maximum encoded size of messages (where known) */
|
||||||
|
#define EnvironmentalMeasurement_size 15
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -208,6 +208,11 @@ typedef struct _RadioConfig_UserPreferences {
|
|||||||
bool range_test_plugin_save;
|
bool range_test_plugin_save;
|
||||||
bool store_forward_plugin_enabled;
|
bool store_forward_plugin_enabled;
|
||||||
uint32_t store_forward_plugin_records;
|
uint32_t store_forward_plugin_records;
|
||||||
|
bool environmental_measurement_plugin_measurement_enabled;
|
||||||
|
bool environmental_measurement_plugin_screen_enabled;
|
||||||
|
uint32_t environmental_measurement_plugin_read_error_count_threshold;
|
||||||
|
uint32_t environmental_measurement_plugin_update_interval;
|
||||||
|
uint32_t environmental_measurement_plugin_recovery_interval;
|
||||||
} RadioConfig_UserPreferences;
|
} RadioConfig_UserPreferences;
|
||||||
|
|
||||||
typedef struct _RouteDiscovery {
|
typedef struct _RouteDiscovery {
|
||||||
@ -360,7 +365,7 @@ extern "C" {
|
|||||||
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
|
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
|
||||||
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
||||||
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
||||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
|
||||||
@ -374,7 +379,7 @@ extern "C" {
|
|||||||
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
|
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
|
||||||
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
||||||
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
||||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
|
||||||
@ -460,6 +465,11 @@ extern "C" {
|
|||||||
#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134
|
#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134
|
||||||
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136
|
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136
|
||||||
#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137
|
#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137
|
||||||
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140
|
||||||
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141
|
||||||
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142
|
||||||
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143
|
||||||
|
#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144
|
||||||
#define RouteDiscovery_route_tag 2
|
#define RouteDiscovery_route_tag 2
|
||||||
#define User_id_tag 1
|
#define User_id_tag 1
|
||||||
#define User_long_name_tag 2
|
#define User_long_name_tag 2
|
||||||
@ -641,7 +651,12 @@ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \
|
|||||||
X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \
|
X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \
|
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \
|
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137)
|
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144)
|
||||||
#define RadioConfig_UserPreferences_CALLBACK NULL
|
#define RadioConfig_UserPreferences_CALLBACK NULL
|
||||||
#define RadioConfig_UserPreferences_DEFAULT NULL
|
#define RadioConfig_UserPreferences_DEFAULT NULL
|
||||||
|
|
||||||
@ -753,13 +768,13 @@ extern const pb_msgdesc_t ToRadio_msg;
|
|||||||
#define SubPacket_size 275
|
#define SubPacket_size 275
|
||||||
#define MeshPacket_size 322
|
#define MeshPacket_size 322
|
||||||
#define ChannelSettings_size 95
|
#define ChannelSettings_size 95
|
||||||
#define RadioConfig_size 405
|
#define RadioConfig_size 432
|
||||||
#define RadioConfig_UserPreferences_size 305
|
#define RadioConfig_UserPreferences_size 332
|
||||||
#define NodeInfo_size 132
|
#define NodeInfo_size 132
|
||||||
#define MyNodeInfo_size 106
|
#define MyNodeInfo_size 106
|
||||||
#define LogRecord_size 81
|
#define LogRecord_size 81
|
||||||
#define FromRadio_size 414
|
#define FromRadio_size 441
|
||||||
#define ToRadio_size 409
|
#define ToRadio_size 436
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
@ -21,6 +21,7 @@ typedef enum _PortNum {
|
|||||||
PortNum_SERIAL_APP = 64,
|
PortNum_SERIAL_APP = 64,
|
||||||
PortNum_STORE_FORWARD_APP = 65,
|
PortNum_STORE_FORWARD_APP = 65,
|
||||||
PortNum_RANGE_TEST_APP = 66,
|
PortNum_RANGE_TEST_APP = 66,
|
||||||
|
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67,
|
||||||
PortNum_PRIVATE_APP = 256,
|
PortNum_PRIVATE_APP = 256,
|
||||||
PortNum_ATAK_FORWARDER = 257
|
PortNum_ATAK_FORWARDER = 257
|
||||||
} PortNum;
|
} PortNum;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "plugins/TextMessagePlugin.h"
|
#include "plugins/TextMessagePlugin.h"
|
||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
|
#include "plugins/esp32/EnvironmentalMeasurementPlugin.h"
|
||||||
#include "plugins/esp32/RangeTestPlugin.h"
|
#include "plugins/esp32/RangeTestPlugin.h"
|
||||||
#include "plugins/SerialPlugin.h"
|
#include "plugins/SerialPlugin.h"
|
||||||
#include "plugins/StoreForwardPlugin.h"
|
#include "plugins/StoreForwardPlugin.h"
|
||||||
@ -40,5 +41,6 @@ void setupPlugins()
|
|||||||
|
|
||||||
new RangeTestPlugin();
|
new RangeTestPlugin();
|
||||||
// new StoreForwardPlugin();
|
// new StoreForwardPlugin();
|
||||||
|
new EnvironmentalMeasurementPlugin();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
209
src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp
Normal file
209
src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
#include "EnvironmentalMeasurementPlugin.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "RTC.h"
|
||||||
|
#include "Router.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||||
|
#include <DHT.h>
|
||||||
|
#include <OLEDDisplay.h>
|
||||||
|
#include <OLEDDisplayUi.h>
|
||||||
|
|
||||||
|
EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin;
|
||||||
|
EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio;
|
||||||
|
|
||||||
|
EnvironmentalMeasurementPlugin::EnvironmentalMeasurementPlugin() : concurrency::OSThread("EnvironmentalMeasurementPlugin") {}
|
||||||
|
|
||||||
|
uint32_t sensor_read_error_count = 0;
|
||||||
|
|
||||||
|
#define DHT_11_GPIO_PIN 13
|
||||||
|
#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 // Some sensors (the DHT11) have a minimum required duration between read attempts
|
||||||
|
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||||
|
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||||
|
|
||||||
|
DHT dht(DHT_11_GPIO_PIN,DHT11);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAS_EINK
|
||||||
|
// The screen is bigger so use bigger fonts
|
||||||
|
#define FONT_SMALL ArialMT_Plain_16
|
||||||
|
#define FONT_MEDIUM ArialMT_Plain_24
|
||||||
|
#define FONT_LARGE ArialMT_Plain_24
|
||||||
|
#else
|
||||||
|
#define FONT_SMALL ArialMT_Plain_10
|
||||||
|
#define FONT_MEDIUM ArialMT_Plain_16
|
||||||
|
#define FONT_LARGE ArialMT_Plain_24
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define fontHeight(font) ((font)[1] + 1) // height is position 1
|
||||||
|
|
||||||
|
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
|
||||||
|
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
|
||||||
|
|
||||||
|
|
||||||
|
int32_t EnvironmentalMeasurementPlugin::runOnce() {
|
||||||
|
#ifndef NO_ESP32 // this only works on ESP32 devices
|
||||||
|
|
||||||
|
/*
|
||||||
|
Uncomment the preferences below if you want to use the plugin
|
||||||
|
without having to configure it from the PythonAPI or WebUI.
|
||||||
|
*/
|
||||||
|
/*radioConfig.preferences.environmental_measurement_plugin_measurement_enabled = 1;
|
||||||
|
radioConfig.preferences.environmental_measurement_plugin_screen_enabled = 1;
|
||||||
|
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5;
|
||||||
|
radioConfig.preferences.environmental_measurement_plugin_update_interval = 30;
|
||||||
|
radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600;*/
|
||||||
|
|
||||||
|
if (! (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
|
||||||
|
// If this plugin is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
|
||||||
|
return (INT32_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
// This is the first time the OSThread library has called this function, so do some setup
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement: Initializing\n");
|
||||||
|
environmentalMeasurementPluginRadio = new EnvironmentalMeasurementPluginRadio();
|
||||||
|
firstTime = 0;
|
||||||
|
// begin reading measurements from the sensor
|
||||||
|
// DHT have a max read-rate of 1HZ, so we should wait at least 1 second
|
||||||
|
// after initializing the sensor before we try to read from it.
|
||||||
|
// returning the interval here means that the next time OSThread
|
||||||
|
// calls our plugin, we'll run the other branch of this if statement
|
||||||
|
// and actually do a "sendOurEnvironmentalMeasurement()"
|
||||||
|
if (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled)
|
||||||
|
{
|
||||||
|
// it's possible to have this plugin enabled, only for displaying values on the screen.
|
||||||
|
// therefore, we should only enable the sensor loop if measurement is also enabled
|
||||||
|
dht.begin();
|
||||||
|
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||||
|
}
|
||||||
|
return (INT32_MAX);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!radioConfig.preferences.environmental_measurement_plugin_measurement_enabled)
|
||||||
|
{
|
||||||
|
// if we somehow got to a second run of this plugin with measurement disabled, then just wait forever
|
||||||
|
// I can't imagine we'd ever get here though.
|
||||||
|
return (INT32_MAX);
|
||||||
|
}
|
||||||
|
// this is not the first time OSThread library has called this function
|
||||||
|
// so just do what we intend to do on the interval
|
||||||
|
if(sensor_read_error_count > radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold)
|
||||||
|
{
|
||||||
|
if (radioConfig.preferences.environmental_measurement_plugin_recovery_interval > 0 ) {
|
||||||
|
DEBUG_MSG(
|
||||||
|
"EnvironmentalMeasurement: TEMPORARILY DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Will retry reads in %d seconds\n",
|
||||||
|
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold,
|
||||||
|
radioConfig.preferences.environmental_measurement_plugin_recovery_interval);
|
||||||
|
return(radioConfig.preferences.environmental_measurement_plugin_recovery_interval*1000);
|
||||||
|
}
|
||||||
|
DEBUG_MSG(
|
||||||
|
"EnvironmentalMeasurement: DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Reads will not be retried until after device reset\n",
|
||||||
|
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold);
|
||||||
|
return(INT32_MAX);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (sensor_read_error_count > 0){
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement: There have been %d sensor read failures. Will retry %d more times\n",
|
||||||
|
sensor_read_error_count,
|
||||||
|
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold-sensor_read_error_count);
|
||||||
|
}
|
||||||
|
if (! environmentalMeasurementPluginRadio->sendOurEnvironmentalMeasurement() ){
|
||||||
|
// if we failed to read the sensor, then try again
|
||||||
|
// as soon as we can according to the maximum polling frequency
|
||||||
|
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The return of runOnce is an int32 representing the desired number of
|
||||||
|
// miliseconds until the function should be called again by the
|
||||||
|
// OSThread library. Multiply the preference value by 1000 to convert seconds to miliseconds
|
||||||
|
return(radioConfig.preferences.environmental_measurement_plugin_update_interval * 1000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EnvironmentalMeasurementPluginRadio::wantUIFrame() {
|
||||||
|
return radioConfig.preferences.environmental_measurement_plugin_screen_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
|
{
|
||||||
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display->setFont(FONT_MEDIUM);
|
||||||
|
display->drawString(x, y, "Environment");
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": T:"+ String(lastMeasurement.temperature,2) + " H:" + String(lastMeasurement.relative_humidity,2));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
String GetSenderName(const MeshPacket &mp) {
|
||||||
|
String sender;
|
||||||
|
|
||||||
|
if (nodeDB.getNode(mp.from)){
|
||||||
|
sender = nodeDB.getNode(mp.from)->user.short_name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sender = "UNK";
|
||||||
|
}
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p)
|
||||||
|
{
|
||||||
|
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
|
||||||
|
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool wasBroadcast = mp.to == NODENUM_BROADCAST;
|
||||||
|
|
||||||
|
String sender = GetSenderName(mp);
|
||||||
|
|
||||||
|
// Show new nodes on LCD screen
|
||||||
|
if (DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN && wasBroadcast) {
|
||||||
|
String lcd = String("Env Measured: ") +sender + "\n" +
|
||||||
|
"T: " + p.temperature + "\n" +
|
||||||
|
"H: " + p.relative_humidity + "\n";
|
||||||
|
screen->print(lcd.c_str());
|
||||||
|
}
|
||||||
|
DEBUG_MSG("-----------------------------------------\n");
|
||||||
|
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement: Received data from %s\n", sender);
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p.relative_humidity);
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p.temperature);
|
||||||
|
|
||||||
|
lastMeasurement = p;
|
||||||
|
lastSender = sender;
|
||||||
|
return false; // Let others look at this message also if they want
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies)
|
||||||
|
{
|
||||||
|
EnvironmentalMeasurement m;
|
||||||
|
|
||||||
|
m.barometric_pressure = 0; // TODO: Add support for barometric sensors
|
||||||
|
m.relative_humidity = dht.readHumidity();
|
||||||
|
m.temperature = dht.readTemperature();;
|
||||||
|
|
||||||
|
DEBUG_MSG("-----------------------------------------\n");
|
||||||
|
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement: Read data\n");
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity);
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature);
|
||||||
|
|
||||||
|
if (isnan(m.relative_humidity) || isnan(m.temperature) ){
|
||||||
|
sensor_read_error_count++;
|
||||||
|
DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor_read_error_count = 0;
|
||||||
|
|
||||||
|
MeshPacket *p = allocDataProtobuf(m);
|
||||||
|
p->to = dest;
|
||||||
|
p->decoded.want_response = wantReplies;
|
||||||
|
|
||||||
|
service.sendToMesh(p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
63
src/plugins/esp32/EnvironmentalMeasurementPlugin.h
Normal file
63
src/plugins/esp32/EnvironmentalMeasurementPlugin.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ProtobufPlugin.h"
|
||||||
|
#include "../mesh/generated/environmental_measurement.pb.h"
|
||||||
|
#include <OLEDDisplay.h>
|
||||||
|
#include <OLEDDisplayUi.h>
|
||||||
|
|
||||||
|
|
||||||
|
class EnvironmentalMeasurementPlugin : private concurrency::OSThread
|
||||||
|
{
|
||||||
|
bool firstTime = 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EnvironmentalMeasurementPlugin();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int32_t runOnce();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EnvironmentalMeasurementPluginRadio plugin for sending/receiving environmental measurements to/from the mesh
|
||||||
|
*/
|
||||||
|
class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin<EnvironmentalMeasurement>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
EnvironmentalMeasurementPluginRadio() : ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) {
|
||||||
|
lastMeasurement.barometric_pressure = nanf("");
|
||||||
|
lastMeasurement.relative_humidity = nanf("");
|
||||||
|
lastMeasurement.temperature = nanf("");
|
||||||
|
lastSender = "N/A";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send our EnvironmentalMeasurement into the mesh
|
||||||
|
*/
|
||||||
|
bool sendOurEnvironmentalMeasurement(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||||
|
|
||||||
|
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** Called to handle a particular incoming message
|
||||||
|
|
||||||
|
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||||
|
*/
|
||||||
|
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p);
|
||||||
|
|
||||||
|
virtual bool wantUIFrame();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
EnvironmentalMeasurement lastMeasurement;
|
||||||
|
|
||||||
|
String lastSender;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
extern EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio;
|
Loading…
Reference in New Issue
Block a user