mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-03 08:30:45 +00:00
Stay up-to-date wrt master (cc @mc-hamster)
# Conflicts: # src/plugins/Plugins.cpp # src/plugins/RangeTestPlugin.cpp # src/plugins/StoreForwardPlugin.cpp
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <assert.h>
|
||||
//#include <assert.h>
|
||||
|
||||
/*
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#include "plugins/ExternalNotificationPlugin.h"
|
||||
#include "plugins/NodeInfoPlugin.h"
|
||||
#include "plugins/PositionPlugin.h"
|
||||
#include "plugins/RangeTestPlugin.h"
|
||||
#include "plugins/RemoteHardwarePlugin.h"
|
||||
#include "plugins/ReplyPlugin.h"
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
#ifndef NO_ESP32
|
||||
#include "plugins/esp32/EnvironmentalMeasurementPlugin.h"
|
||||
#include "plugins/esp32/RangeTestPlugin.h"
|
||||
#endif
|
||||
#include "plugins/SerialPlugin.h"
|
||||
#include "plugins/StoreForwardPlugin.h"
|
||||
#include "plugins/TextMessagePlugin.h"
|
||||
@@ -35,7 +39,12 @@ void setupPlugins()
|
||||
*/
|
||||
new SerialPlugin();
|
||||
new ExternalNotificationPlugin();
|
||||
//storeForwardPlugin = new StoreForwardPlugin();
|
||||
rangeTestPlugin = new RangeTestPlugin();
|
||||
|
||||
// rangeTestPlugin = new RangeTestPlugin();
|
||||
storeForwardPlugin = new StoreForwardPlugin();
|
||||
|
||||
new RangeTestPlugin();
|
||||
// new StoreForwardPlugin();
|
||||
new EnvironmentalMeasurementPlugin();
|
||||
#endif
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
#include "RangeTestPlugin.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
As a sender, I can send packets every n-seonds. These packets include an incramented PacketID.
|
||||
|
||||
As a receiver, I can receive packets from multiple senders. These packets can be saved to the spiffs.
|
||||
|
||||
*/
|
||||
|
||||
RangeTestPlugin *rangeTestPlugin;
|
||||
RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
|
||||
RangeTestPlugin::RangeTestPlugin() : concurrency::OSThread("RangeTestPlugin") {}
|
||||
|
||||
uint16_t packetSequence = 0;
|
||||
|
||||
// char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||
|
||||
int32_t RangeTestPlugin::runOnce()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// radioConfig.preferences.range_test_plugin_enabled = 1;
|
||||
// radioConfig.preferences.range_test_plugin_sender = 0;
|
||||
// radioConfig.preferences.fixed_position = 1;
|
||||
|
||||
uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000;
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
// Interface with the serial peripheral from in here.
|
||||
|
||||
rangeTestPluginRadio = new RangeTestPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_sender) {
|
||||
DEBUG_MSG("Initializing Range Test Plugin -- Sender\n");
|
||||
return (senderHeartbeat);
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Range Test Plugin -- Receiver\n");
|
||||
return (500);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_sender) {
|
||||
// If sender
|
||||
DEBUG_MSG("Range Test Plugin - Sending heartbeat every %d ms\n", (senderHeartbeat));
|
||||
|
||||
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("pref.fixed_position() %d\n", radioConfig.preferences.fixed_position);
|
||||
|
||||
rangeTestPluginRadio->sendPayload();
|
||||
return ((senderHeartbeat));
|
||||
} else {
|
||||
// Otherwise, we're a receiver.
|
||||
|
||||
return (500);
|
||||
}
|
||||
// TBD
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Range Test Plugin - Disabled\n");
|
||||
}
|
||||
|
||||
return (INT32_MAX);
|
||||
#endif
|
||||
}
|
||||
|
||||
MeshPacket *RangeTestPluginRadio::allocReply()
|
||||
{
|
||||
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
p->want_ack = true;
|
||||
|
||||
packetSequence++;
|
||||
|
||||
static char heartbeatString[20];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "seq %d", packetSequence);
|
||||
|
||||
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, heartbeatString, p->decoded.payload.size);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_enabled) {
|
||||
|
||||
auto &p = mp.decoded;
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
|
||||
|
||||
if (mp.from != nodeDB.getNodeNum()) {
|
||||
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
// Serial2.printf("%s", p.payload.bytes);
|
||||
/*
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
NodeInfo *n = nodeDB.getNode(mp.from);
|
||||
|
||||
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
|
||||
DEBUG_MSG("p.payload.size %d\n", p.payload.size);
|
||||
DEBUG_MSG("---- Received Packet:\n");
|
||||
DEBUG_MSG("mp.from %d\n", mp.from);
|
||||
DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr);
|
||||
DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit);
|
||||
//deprecated and unpopulated for sometime
|
||||
//DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i);
|
||||
//DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i);
|
||||
DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n");
|
||||
DEBUG_MSG("n->user.long_name %s\n", n->user.long_name);
|
||||
DEBUG_MSG("n->user.short_name %s\n", n->user.short_name);
|
||||
DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr);
|
||||
DEBUG_MSG("n->has_position %d\n", n->has_position);
|
||||
DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i);
|
||||
DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i);
|
||||
DEBUG_MSG("n->position.battery_level %d\n", n->position.battery_level);
|
||||
DEBUG_MSG("---- Current device location information:\n");
|
||||
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Range Test Plugin Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return true; // Let others look at this message also if they want
|
||||
}
|
||||
@@ -5,31 +5,16 @@
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define STORE_RECORDS 5000
|
||||
#define BYTES_PER_RECORDS 512
|
||||
|
||||
struct sfRecord
|
||||
{
|
||||
uint8_t bytes[BYTES_PER_RECORDS];
|
||||
uint32_t timestamp; // Time the packet was received
|
||||
};
|
||||
|
||||
struct sfRecord records[STORE_RECORDS];
|
||||
|
||||
#define STOREFORWARDPLUGIN_ENABLED 0
|
||||
#include <map>
|
||||
|
||||
StoreForwardPlugin *storeForwardPlugin;
|
||||
StoreForwardPluginRadio *storeForwardPluginRadio;
|
||||
|
||||
StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("SerialPlugin") {}
|
||||
|
||||
// char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||
StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPlugin") {}
|
||||
|
||||
int32_t StoreForwardPlugin::runOnce()
|
||||
{
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
@@ -37,21 +22,25 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
//radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
//radioConfig.preferences.store_forward_plugin_records = 80;
|
||||
// radioConfig.preferences.store_forward_plugin_enabled = 1;
|
||||
// radioConfig.preferences.is_router = 1;
|
||||
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
// Interface with the serial peripheral from in here.
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin\n");
|
||||
/*
|
||||
*/
|
||||
|
||||
// Router
|
||||
if (radioConfig.preferences.is_router) {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled\n");
|
||||
// Router
|
||||
if (ESP.getPsramSize()) {
|
||||
if (ESP.getFreePsram() <= 1024 * 1024) {
|
||||
if (ESP.getFreePsram() >= 1024 * 1024) {
|
||||
// Do the startup here
|
||||
storeForwardPluginRadio = new StoreForwardPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n");
|
||||
@@ -67,20 +56,21 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
// Non-Router
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Store & Forward Plugin - Enabled but is_router is not turned on.\n");
|
||||
DEBUG_MSG(
|
||||
"Initializing Store & Forward Plugin - If you want to use this plugin, you must also turn on is_router.\n");
|
||||
// Non-Router
|
||||
|
||||
return (30 * 1000);
|
||||
}
|
||||
|
||||
storeForwardPluginRadio = new StoreForwardPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
} else {
|
||||
// TBD
|
||||
// What do we do if it's not our first time?
|
||||
|
||||
// Maybe some cleanup functions?
|
||||
}
|
||||
|
||||
return (10);
|
||||
} else {
|
||||
DEBUG_MSG("Store & Forward Plugin - Disabled\n");
|
||||
|
||||
@@ -88,6 +78,44 @@ int32_t StoreForwardPlugin::runOnce()
|
||||
}
|
||||
|
||||
#endif
|
||||
return (INT32_MAX);
|
||||
}
|
||||
|
||||
// We saw a node.
|
||||
uint32_t StoreForwardPlugin::sawNode(uint32_t node)
|
||||
{
|
||||
|
||||
/*
|
||||
TODO: Move receivedRecord into the PSRAM
|
||||
|
||||
TODO: Gracefully handle the case where we run out of records.
|
||||
Maybe replace the oldest record that hasn't been seen in a while and assume they won't be back.
|
||||
|
||||
TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?).
|
||||
*/
|
||||
|
||||
DEBUG_MSG("looking for node - %i\n", node);
|
||||
for (int i = 0; i < 50; i++) {
|
||||
DEBUG_MSG("Iterating through the seen nodes - %d %d %d\n", i, receivedRecord[i][0], receivedRecord[i][1]);
|
||||
// First time seeing that node.
|
||||
if (receivedRecord[i][0] == 0) {
|
||||
DEBUG_MSG("New node! Woohoo! Win!\n");
|
||||
receivedRecord[i][0] = node;
|
||||
receivedRecord[i][1] = millis();
|
||||
|
||||
return receivedRecord[i][1];
|
||||
}
|
||||
|
||||
// We've seen this node before.
|
||||
if (receivedRecord[i][0] == node) {
|
||||
DEBUG_MSG("We've seen this node before\n");
|
||||
uint32_t lastSaw = receivedRecord[i][1];
|
||||
receivedRecord[i][1] = millis();
|
||||
return lastSaw;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MeshPacket *StoreForwardPluginRadio::allocReply()
|
||||
@@ -104,50 +132,25 @@ void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
//p->want_ack = SERIALPLUGIN_ACK;
|
||||
|
||||
// p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply
|
||||
// memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
if (radioConfig.preferences.store_forward_plugin_enabled) {
|
||||
// auto &p = mp.decoded.data;
|
||||
|
||||
if (STOREFORWARDPLUGIN_ENABLED) {
|
||||
|
||||
auto &p = mp.decoded;
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
|
||||
|
||||
if (mp.from == nodeDB.getNodeNum()) {
|
||||
|
||||
/*
|
||||
* If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX
|
||||
* of the serial interface.
|
||||
*/
|
||||
if (radioConfig.preferences.serialplugin_echo) {
|
||||
|
||||
// For some reason, we get the packet back twice when we send out of the radio.
|
||||
// TODO: need to find out why.
|
||||
if (lastRxID != mp.id) {
|
||||
lastRxID = mp.id;
|
||||
// DEBUG_MSG("* * Message came this device\n");
|
||||
// Serial2.println("* * Message came this device");
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
if (mp.from != nodeDB.getNodeNum()) {
|
||||
DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n");
|
||||
printPacket("----- PACKET FROM RADIO", &mp);
|
||||
// DEBUG_MSG("\n\nStore & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n");
|
||||
uint32_t sawTime = storeForwardPlugin->sawNode(mp.from);
|
||||
DEBUG_MSG("Last Saw this node %d, %d millis ago\n", mp.from, (millis() - sawTime));
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Serial Plugin Disabled\n");
|
||||
DEBUG_MSG("Store & Forward Plugin - Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,9 +10,22 @@ class StoreForwardPlugin : private concurrency::OSThread
|
||||
{
|
||||
bool firstTime = 1;
|
||||
|
||||
// TODO: Move this into the PSRAM
|
||||
// TODO: Allow configuration of the maximum number of records.
|
||||
uint32_t receivedRecord[50][2] = {{0}};
|
||||
|
||||
public:
|
||||
StoreForwardPlugin();
|
||||
|
||||
/**
|
||||
Update our local reference of when we last saw that node.
|
||||
@return 0 if we have never seen that node before otherwise return the last time we saw the node.
|
||||
*/
|
||||
uint32_t sawNode(uint32_t);
|
||||
|
||||
private:
|
||||
// Nothing here
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce();
|
||||
};
|
||||
@@ -20,21 +33,16 @@ class StoreForwardPlugin : private concurrency::OSThread
|
||||
extern StoreForwardPlugin *storeForwardPlugin;
|
||||
|
||||
/*
|
||||
* Radio interface for SerialPlugin
|
||||
* Radio interface for StoreForwardPlugin
|
||||
*
|
||||
*/
|
||||
class StoreForwardPluginRadio : public SinglePortPlugin
|
||||
{
|
||||
uint32_t lastRxID;
|
||||
// uint32_t lastRxID;
|
||||
|
||||
public:
|
||||
/*
|
||||
TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here
|
||||
from the main code.
|
||||
*/
|
||||
|
||||
// SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
StoreForwardPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {}
|
||||
StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {}
|
||||
// StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
/**
|
||||
* Send our payload into the mesh
|
||||
@@ -44,6 +52,8 @@ class StoreForwardPluginRadio : public SinglePortPlugin
|
||||
protected:
|
||||
virtual MeshPacket *allocReply();
|
||||
|
||||
virtual bool wantPortnum(PortNum p) { return true; };
|
||||
|
||||
/** 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
|
||||
@@ -51,4 +61,4 @@ class StoreForwardPluginRadio : public SinglePortPlugin
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern StoreForwardPluginRadio *storeForwardPluginRadio;
|
||||
extern StoreForwardPluginRadio *storeForwardPluginRadio;
|
||||
|
||||
102
src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp
Normal file
102
src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#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>
|
||||
|
||||
EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin;
|
||||
EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio;
|
||||
|
||||
EnvironmentalMeasurementPlugin::EnvironmentalMeasurementPlugin() : concurrency::OSThread("EnvironmentalMeasurementPlugin") {}
|
||||
|
||||
uint32_t sensor_read_error_count = 0;
|
||||
|
||||
#define DHT_11_GPIO_PIN 13
|
||||
//TODO: Make a related radioconfig preference to allow less-frequent reads
|
||||
#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
|
||||
#define SENSOR_READ_ERROR_COUNT_THRESHOLD 5
|
||||
#define SENSOR_READ_MULTIPLIER 3
|
||||
|
||||
|
||||
DHT dht(DHT_11_GPIO_PIN,DHT11);
|
||||
|
||||
int32_t EnvironmentalMeasurementPlugin::runOnce() {
|
||||
#ifndef NO_ESP32
|
||||
if (firstTime) {
|
||||
// This is the first time the OSThread library has called this function, so do some setup
|
||||
DEBUG_MSG("Initializing Environmental Measurement Plugin -- Sender\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()"
|
||||
dht.begin();
|
||||
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
else {
|
||||
// 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 > SENSOR_READ_ERROR_COUNT_THRESHOLD)
|
||||
{
|
||||
DEBUG_MSG("Environmental Measurement Plugin: DISABLED; The SENSOR_READ_ERROR_COUNT_THRESHOLD has been exceed: %d\n",SENSOR_READ_ERROR_COUNT_THRESHOLD);
|
||||
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
}
|
||||
else if (sensor_read_error_count > 0){
|
||||
DEBUG_MSG("Environmental Measurement Plugin: There have been %d sensor read failures.\n",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.
|
||||
return(SENSOR_READ_MULTIPLIER * DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p)
|
||||
{
|
||||
// This plugin doesn't really do anything with the messages it receives.
|
||||
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("Environmental Measurement Plugin: 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("Environmental Measurement Plugin: 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;
|
||||
}
|
||||
|
||||
45
src/plugins/esp32/EnvironmentalMeasurementPlugin.h
Normal file
45
src/plugins/esp32/EnvironmentalMeasurementPlugin.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include "ProtobufPlugin.h"
|
||||
#include "../mesh/generated/environmental_measurement.pb.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) {}
|
||||
|
||||
/**
|
||||
* Send our EnvironmentalMeasurement into the mesh
|
||||
*/
|
||||
bool sendOurEnvironmentalMeasurement(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
extern EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio;
|
||||
315
src/plugins/esp32/RangeTestPlugin.cpp
Normal file
315
src/plugins/esp32/RangeTestPlugin.cpp
Normal file
@@ -0,0 +1,315 @@
|
||||
#include "RangeTestPlugin.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
#include <SPIFFS.h>
|
||||
//#include <assert.h>
|
||||
|
||||
/*
|
||||
As a sender, I can send packets every n-seonds. These packets include an incramented PacketID.
|
||||
|
||||
As a receiver, I can receive packets from multiple senders. These packets can be saved to the spiffs.
|
||||
*/
|
||||
|
||||
RangeTestPlugin *rangeTestPlugin;
|
||||
RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
|
||||
RangeTestPlugin::RangeTestPlugin() : concurrency::OSThread("RangeTestPlugin") {}
|
||||
|
||||
uint32_t packetSequence = 0;
|
||||
|
||||
#define SEC_PER_DAY 86400
|
||||
#define SEC_PER_HOUR 3600
|
||||
#define SEC_PER_MIN 60
|
||||
|
||||
int32_t RangeTestPlugin::runOnce()
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the plugin
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
//radioConfig.preferences.range_test_plugin_enabled = 1;
|
||||
//radioConfig.preferences.range_test_plugin_sender = 45;
|
||||
//radioConfig.preferences.range_test_plugin_save = 1;
|
||||
|
||||
// Fixed position is useful when testing indoors.
|
||||
// radioConfig.preferences.fixed_position = 1;
|
||||
|
||||
uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000;
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_enabled) {
|
||||
|
||||
if (firstTime) {
|
||||
|
||||
// Interface with the serial peripheral from in here.
|
||||
|
||||
rangeTestPluginRadio = new RangeTestPluginRadio();
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_sender) {
|
||||
DEBUG_MSG("Initializing Range Test Plugin -- Sender\n");
|
||||
return (5000); // Sending first message 5 seconds after initilization.
|
||||
} else {
|
||||
DEBUG_MSG("Initializing Range Test Plugin -- Receiver\n");
|
||||
return (500);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_sender) {
|
||||
// If sender
|
||||
DEBUG_MSG("Range Test Plugin - Sending heartbeat every %d ms\n", (senderHeartbeat));
|
||||
|
||||
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("pref.fixed_position() %d\n", radioConfig.preferences.fixed_position);
|
||||
|
||||
rangeTestPluginRadio->sendPayload();
|
||||
return (senderHeartbeat);
|
||||
} else {
|
||||
// Otherwise, we're a receiver.
|
||||
|
||||
return (500);
|
||||
}
|
||||
// TBD
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Range Test Plugin - Disabled\n");
|
||||
}
|
||||
|
||||
return (INT32_MAX);
|
||||
#endif
|
||||
}
|
||||
|
||||
MeshPacket *RangeTestPluginRadio::allocReply()
|
||||
{
|
||||
|
||||
auto reply = allocDataPacket(); // Allocate a packet for sending
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
p->want_ack = true;
|
||||
|
||||
packetSequence++;
|
||||
|
||||
static char heartbeatString[20];
|
||||
snprintf(heartbeatString, sizeof(heartbeatString), "seq %d", packetSequence);
|
||||
|
||||
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, heartbeatString, p->decoded.payload.size);
|
||||
|
||||
service.sendToMesh(p);
|
||||
|
||||
// TODO: Handle this better. We want to keep the phone awake otherwise it stops sending.
|
||||
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
|
||||
}
|
||||
|
||||
bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#ifndef NO_ESP32
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_enabled) {
|
||||
|
||||
auto &p = mp.decoded;
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
|
||||
|
||||
if (mp.from != nodeDB.getNodeNum()) {
|
||||
|
||||
// DEBUG_MSG("* * Message came from the mesh\n");
|
||||
// Serial2.println("* * Message came from the mesh");
|
||||
// Serial2.printf("%s", p.payload.bytes);
|
||||
/*
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
NodeInfo *n = nodeDB.getNode(mp.from);
|
||||
|
||||
if (radioConfig.preferences.range_test_plugin_save) {
|
||||
appendFile(mp);
|
||||
}
|
||||
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
|
||||
DEBUG_MSG("p.payload.size %d\n", p.payload.size);
|
||||
DEBUG_MSG("---- Received Packet:\n");
|
||||
DEBUG_MSG("mp.from %d\n", mp.from);
|
||||
DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr);
|
||||
DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit);
|
||||
// DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated
|
||||
// DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated
|
||||
DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n");
|
||||
DEBUG_MSG("n->user.long_name %s\n", n->user.long_name);
|
||||
DEBUG_MSG("n->user.short_name %s\n", n->user.short_name);
|
||||
// DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr);
|
||||
DEBUG_MSG("n->has_position %d\n", n->has_position);
|
||||
DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i);
|
||||
DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i);
|
||||
DEBUG_MSG("n->position.battery_level %d\n", n->position.battery_level);
|
||||
DEBUG_MSG("---- Current device location information:\n");
|
||||
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Range Test Plugin Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return true; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
/// Ported from my old java code, returns distance in meters along the globe
|
||||
/// surface (by magic?)
|
||||
float RangeTestPluginRadio::latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
|
||||
{
|
||||
double pk = (180 / 3.14169);
|
||||
double a1 = lat_a / pk;
|
||||
double a2 = lng_a / pk;
|
||||
double b1 = lat_b / pk;
|
||||
double b2 = lng_b / pk;
|
||||
double cos_b1 = cos(b1);
|
||||
double cos_a1 = cos(a1);
|
||||
double t1 = cos_a1 * cos(a2) * cos_b1 * cos(b2);
|
||||
double t2 = cos_a1 * sin(a2) * cos_b1 * sin(b2);
|
||||
double t3 = sin(a1) * sin(b1);
|
||||
double tt = acos(t1 + t2 + t3);
|
||||
if (isnan(tt))
|
||||
tt = 0.0; // Must have been the same point?
|
||||
|
||||
return (float)(6366000 * tt);
|
||||
}
|
||||
|
||||
bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
|
||||
{
|
||||
auto &p = mp.decoded;
|
||||
|
||||
NodeInfo *n = nodeDB.getNode(mp.from);
|
||||
/*
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
|
||||
DEBUG_MSG("p.payload.size %d\n", p.payload.size);
|
||||
DEBUG_MSG("---- Received Packet:\n");
|
||||
DEBUG_MSG("mp.from %d\n", mp.from);
|
||||
DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr);
|
||||
DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit);
|
||||
// DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated
|
||||
// DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated
|
||||
DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n");
|
||||
DEBUG_MSG("n->user.long_name %s\n", n->user.long_name);
|
||||
DEBUG_MSG("n->user.short_name %s\n", n->user.short_name);
|
||||
DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr);
|
||||
DEBUG_MSG("n->has_position %d\n", n->has_position);
|
||||
DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i);
|
||||
DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i);
|
||||
DEBUG_MSG("n->position.battery_level %d\n", n->position.battery_level);
|
||||
DEBUG_MSG("---- Current device location information:\n");
|
||||
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
||||
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
||||
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
||||
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
||||
DEBUG_MSG("-----------------------------------------\n");
|
||||
*/
|
||||
if (!SPIFFS.begin(true)) {
|
||||
DEBUG_MSG("An Error has occurred while mounting SPIFFS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < 51200) {
|
||||
DEBUG_MSG("SPIFFS doesn't have enough free space. Abourting write.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the file doesn't exist, write the header.
|
||||
if (!SPIFFS.exists("/static/rangetest.csv")) {
|
||||
//--------- Write to file
|
||||
File fileToWrite = SPIFFS.open("/static/rangetest.csv", FILE_WRITE);
|
||||
|
||||
if (!fileToWrite) {
|
||||
DEBUG_MSG("There was an error opening the file for writing\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fileToWrite.println("time,from,sender name,sender lat,sender long,rx lat,rx long,rx snr,distance,payload")) {
|
||||
DEBUG_MSG("File was written\n");
|
||||
} else {
|
||||
DEBUG_MSG("File write failed\n");
|
||||
}
|
||||
|
||||
fileToWrite.close();
|
||||
}
|
||||
|
||||
//--------- Apend content to file
|
||||
File fileToAppend = SPIFFS.open("/static/rangetest.csv", FILE_APPEND);
|
||||
|
||||
if (!fileToAppend) {
|
||||
DEBUG_MSG("There was an error opening the file for appending\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
if (!gettimeofday(&tv, NULL)) {
|
||||
long hms = tv.tv_sec % SEC_PER_DAY;
|
||||
// hms += tz.tz_dsttime * SEC_PER_HOUR;
|
||||
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
|
||||
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
|
||||
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
||||
|
||||
// Tear apart hms into h:m:s
|
||||
int hour = hms / SEC_PER_HOUR;
|
||||
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
||||
|
||||
fileToAppend.printf("%02d:%02d:%02d,", hour, min, sec); // Time
|
||||
} else {
|
||||
fileToAppend.printf("??:??:??,"); // Time
|
||||
}
|
||||
|
||||
fileToAppend.printf("%d,", mp.from); // From
|
||||
fileToAppend.printf("%s,", n->user.long_name); // Long Name
|
||||
fileToAppend.printf("%f,", n->position.latitude_i * 1e-7); // Sender Lat
|
||||
fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long
|
||||
fileToAppend.printf("%f,", gpsStatus->getLatitude() * 1e-7); // RX Lat
|
||||
fileToAppend.printf("%f,", gpsStatus->getLongitude() * 1e-7); // RX Long
|
||||
fileToAppend.printf("%f,", mp.rx_snr); // RX SNR
|
||||
|
||||
if (n->position.latitude_i && n->position.longitude_i && gpsStatus->getLatitude() && gpsStatus->getLongitude()) {
|
||||
float distance = latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7,
|
||||
gpsStatus->getLatitude() * 1e-7, gpsStatus->getLongitude() * 1e-7);
|
||||
fileToAppend.printf("%f,", distance); // Distance in meters
|
||||
} else {
|
||||
fileToAppend.printf("0,");
|
||||
}
|
||||
|
||||
// TODO: If quotes are found in the payload, it has to be escaped.
|
||||
fileToAppend.printf("\"%s\"\n", p.payload.bytes);
|
||||
|
||||
fileToAppend.close();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -28,7 +28,6 @@ class RangeTestPluginRadio : public SinglePortPlugin
|
||||
uint32_t lastRxID;
|
||||
|
||||
public:
|
||||
|
||||
RangeTestPluginRadio() : SinglePortPlugin("RangeTestPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
/**
|
||||
@@ -36,6 +35,16 @@ class RangeTestPluginRadio : public SinglePortPlugin
|
||||
*/
|
||||
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
/**
|
||||
* Append range test data to the file on the spiffs
|
||||
*/
|
||||
bool appendFile(const MeshPacket &mp);
|
||||
|
||||
/**
|
||||
* Kevin's magical calculation of two points to meters.
|
||||
*/
|
||||
float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b);
|
||||
|
||||
protected:
|
||||
virtual MeshPacket *allocReply();
|
||||
|
||||
@@ -46,4 +55,4 @@ class RangeTestPluginRadio : public SinglePortPlugin
|
||||
virtual bool handleReceived(const MeshPacket &mp);
|
||||
};
|
||||
|
||||
extern RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
extern RangeTestPluginRadio *rangeTestPluginRadio;
|
||||
Reference in New Issue
Block a user