mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-07 18:37:52 +00:00
Merge branch 'master' into nomad-gemini
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RTC.h"
|
||||
#include "SPILock.h"
|
||||
#include "meshUtils.h"
|
||||
#include <FSCommon.h>
|
||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
@@ -358,12 +359,15 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
}
|
||||
case meshtastic_AdminMessage_delete_file_request_tag: {
|
||||
LOG_DEBUG("Client requesting to delete file: %s", r->delete_file_request);
|
||||
|
||||
#ifdef FSCom
|
||||
spiLock->lock();
|
||||
if (FSCom.remove(r->delete_file_request)) {
|
||||
LOG_DEBUG("Successfully deleted file");
|
||||
} else {
|
||||
LOG_DEBUG("Failed to delete file");
|
||||
}
|
||||
spiLock->unlock();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,6 @@ void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtast
|
||||
}
|
||||
|
||||
// Decompress for Phone (EUD)
|
||||
auto decompressedCopy = packetPool.allocCopy(mp);
|
||||
auto uncompressed = cloneTAKPacketData(t);
|
||||
uncompressed.is_compressed = false;
|
||||
if (t->has_contact) {
|
||||
@@ -188,6 +187,7 @@ void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtast
|
||||
LOG_DEBUG("Decompressed chat to_callsign: %d bytes", length);
|
||||
}
|
||||
}
|
||||
auto decompressedCopy = packetPool.allocCopy(mp);
|
||||
decompressedCopy->decoded.payload.size =
|
||||
pb_encode_to_bytes(decompressedCopy->decoded.payload.bytes, sizeof(decompressedCopy->decoded.payload),
|
||||
meshtastic_TAKPacket_fields, &uncompressed);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h" // needed for button bypass
|
||||
#include "SPILock.h"
|
||||
#include "detect/ScanI2C.h"
|
||||
#include "input/ScanAndSelect.h"
|
||||
#include "mesh/generated/meshtastic/cannedmessages.pb.h"
|
||||
@@ -982,6 +983,7 @@ bool CannedMessageModule::interceptingKeyboardInput()
|
||||
}
|
||||
}
|
||||
|
||||
#if !HAS_TFT
|
||||
void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
char buffer[50];
|
||||
@@ -1140,6 +1142,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //! HAS_TFT
|
||||
|
||||
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
@@ -1182,8 +1185,10 @@ bool CannedMessageModule::saveProtoForModule()
|
||||
{
|
||||
bool okay = true;
|
||||
|
||||
#ifdef FS
|
||||
FS.mkdir("/prefs");
|
||||
#ifdef FSCom
|
||||
spiLock->lock();
|
||||
FSCom.mkdir("/prefs");
|
||||
spiLock->unlock();
|
||||
#endif
|
||||
|
||||
okay &= nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "PowerFSM.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "SPILock.h"
|
||||
#include "airtime.h"
|
||||
#include "configuration.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
@@ -205,6 +206,7 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
|
||||
LOG_DEBUG("gpsStatus->getDOP() %d", gpsStatus->getDOP());
|
||||
LOG_DEBUG("-----------------------------------------");
|
||||
*/
|
||||
concurrency::LockGuard g(spiLock);
|
||||
if (!FSBegin()) {
|
||||
LOG_DEBUG("An Error has occurred while mounting the filesystem");
|
||||
return 0;
|
||||
|
||||
@@ -13,7 +13,8 @@ class RoutingModule : public ProtobufModule<meshtastic_Routing>
|
||||
*/
|
||||
RoutingModule();
|
||||
|
||||
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0);
|
||||
virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
||||
uint8_t hopLimit = 0);
|
||||
|
||||
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
|
||||
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "Sensor/BMP280Sensor.h"
|
||||
#include "Sensor/BMP3XXSensor.h"
|
||||
#include "Sensor/CGRadSensSensor.h"
|
||||
#include "Sensor/DFRobotGravitySensor.h"
|
||||
#include "Sensor/DFRobotLarkSensor.h"
|
||||
#include "Sensor/LPS22HBSensor.h"
|
||||
#include "Sensor/MCP9808Sensor.h"
|
||||
@@ -56,6 +57,7 @@ RCWL9620Sensor rcwl9620Sensor;
|
||||
AHT10Sensor aht10Sensor;
|
||||
MLX90632Sensor mlx90632Sensor;
|
||||
DFRobotLarkSensor dfRobotLarkSensor;
|
||||
DFRobotGravitySensor dfRobotGravitySensor;
|
||||
NAU7802Sensor nau7802Sensor;
|
||||
BMP3XXSensor bmp3xxSensor;
|
||||
CGRadSensSensor cgRadSens;
|
||||
@@ -64,6 +66,10 @@ CGRadSensSensor cgRadSens;
|
||||
#include "Sensor/T1000xSensor.h"
|
||||
T1000xSensor t1000xSensor;
|
||||
#endif
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
#include "Sensor/IndicatorSensor.h"
|
||||
IndicatorSensor indicatorSensor;
|
||||
#endif
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
|
||||
@@ -103,11 +109,16 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
LOG_INFO("Environment Telemetry: init");
|
||||
// it's possible to have this module enabled, only for displaying values on the screen.
|
||||
// therefore, we should only enable the sensor loop if measurement is also enabled
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
result = indicatorSensor.runOnce();
|
||||
#endif
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
result = t1000xSensor.runOnce();
|
||||
#elif !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
if (dfRobotLarkSensor.hasSensor())
|
||||
result = dfRobotLarkSensor.runOnce();
|
||||
if (dfRobotGravitySensor.hasSensor())
|
||||
result = dfRobotGravitySensor.runOnce();
|
||||
if (bmp085Sensor.hasSensor())
|
||||
result = bmp085Sensor.runOnce();
|
||||
if (bmp280Sensor.hasSensor())
|
||||
@@ -215,7 +226,11 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
}
|
||||
|
||||
// Display "Env. From: ..." on its own
|
||||
display->drawString(x, y, "Env. From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
|
||||
display->drawString(x, y, "Env. From: " + String(lastSender) + " (" + String(agoSecs) + "s)");
|
||||
|
||||
// Prepare sensor data strings
|
||||
String sensorData[10];
|
||||
int sensorCount = 0;
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.has_temperature ||
|
||||
lastMeasurement.variant.environment_metrics.has_relative_humidity) {
|
||||
@@ -225,38 +240,83 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
String(UnitConversions::CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F";
|
||||
}
|
||||
|
||||
// Continue with the remaining details
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Temp/Hum: " + last_temp + " / " +
|
||||
String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%");
|
||||
sensorData[sensorCount++] =
|
||||
"Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA");
|
||||
sensorData[sensorCount++] =
|
||||
"Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.voltage != 0) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " +
|
||||
String(lastMeasurement.variant.environment_metrics.current, 0) + "mA");
|
||||
sensorData[sensorCount++] = "Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " +
|
||||
String(lastMeasurement.variant.environment_metrics.current, 0) + "mA";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.iaq != 0) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq));
|
||||
sensorData[sensorCount++] = "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq);
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.distance != 0)
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm");
|
||||
if (lastMeasurement.variant.environment_metrics.distance != 0) {
|
||||
sensorData[sensorCount++] = "Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.weight != 0)
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg");
|
||||
if (lastMeasurement.variant.environment_metrics.weight != 0) {
|
||||
sensorData[sensorCount++] = "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.radiation != 0)
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Rad: " + String(lastMeasurement.variant.environment_metrics.radiation, 2) + "µR/h");
|
||||
if (lastMeasurement.variant.environment_metrics.radiation != 0) {
|
||||
sensorData[sensorCount++] = "Rad: " + String(lastMeasurement.variant.environment_metrics.radiation, 2) + "µR/h";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.lux != 0) {
|
||||
sensorData[sensorCount++] = "Illuminance: " + String(lastMeasurement.variant.environment_metrics.lux, 2) + "lx";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.white_lux != 0) {
|
||||
sensorData[sensorCount++] = "W_Lux: " + String(lastMeasurement.variant.environment_metrics.white_lux, 2) + "lx";
|
||||
}
|
||||
|
||||
static int scrollOffset = 0;
|
||||
static bool scrollingDown = true;
|
||||
static uint32_t lastScrollTime = millis();
|
||||
|
||||
// Determine how many lines we can fit on display
|
||||
// Calculated once only: display dimensions don't change during runtime.
|
||||
static int maxLines = 0;
|
||||
if (!maxLines) {
|
||||
const int16_t paddingTop = _fontHeight(FONT_SMALL); // Heading text
|
||||
const int16_t paddingBottom = 8; // Indicator dots
|
||||
maxLines = (display->getHeight() - paddingTop - paddingBottom) / _fontHeight(FONT_SMALL);
|
||||
assert(maxLines > 0);
|
||||
}
|
||||
|
||||
// Draw as many lines of data as we can fit
|
||||
int linesToShow = min(maxLines, sensorCount);
|
||||
for (int i = 0; i < linesToShow; i++) {
|
||||
int index = (scrollOffset + i) % sensorCount;
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL), sensorData[index]);
|
||||
}
|
||||
|
||||
// Only scroll if there are more than 3 sensor data lines
|
||||
if (sensorCount > 3) {
|
||||
// Update scroll offset every 5 seconds
|
||||
if (millis() - lastScrollTime > 5000) {
|
||||
if (scrollingDown) {
|
||||
scrollOffset++;
|
||||
if (scrollOffset + linesToShow >= sensorCount) {
|
||||
scrollingDown = false;
|
||||
}
|
||||
} else {
|
||||
scrollOffset--;
|
||||
if (scrollOffset <= 0) {
|
||||
scrollingDown = true;
|
||||
}
|
||||
}
|
||||
lastScrollTime = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||
@@ -270,8 +330,10 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
|
||||
sender, t->variant.environment_metrics.barometric_pressure, t->variant.environment_metrics.current,
|
||||
t->variant.environment_metrics.gas_resistance, t->variant.environment_metrics.relative_humidity,
|
||||
t->variant.environment_metrics.temperature);
|
||||
LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f", sender, t->variant.environment_metrics.voltage,
|
||||
t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance, t->variant.environment_metrics.lux);
|
||||
LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f, white_lux=%f", sender,
|
||||
t->variant.environment_metrics.voltage, t->variant.environment_metrics.iaq,
|
||||
t->variant.environment_metrics.distance, t->variant.environment_metrics.lux,
|
||||
t->variant.environment_metrics.white_lux);
|
||||
|
||||
LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees, weight=%fkg", sender,
|
||||
t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction,
|
||||
@@ -298,6 +360,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
m->which_variant = meshtastic_Telemetry_environment_metrics_tag;
|
||||
m->variant.environment_metrics = meshtastic_EnvironmentMetrics_init_zero;
|
||||
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
valid = valid && indicatorSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
#endif
|
||||
#ifdef T1000X_SENSOR_EN // add by WayenWeng
|
||||
valid = valid && t1000xSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
@@ -306,6 +372,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
valid = valid && dfRobotLarkSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (dfRobotGravitySensor.hasSensor()) {
|
||||
valid = valid && dfRobotGravitySensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (sht31Sensor.hasSensor()) {
|
||||
valid = valid && sht31Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
@@ -410,7 +480,6 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
valid = valid && cgRadSens.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
return valid && hasSensor;
|
||||
}
|
||||
@@ -508,6 +577,11 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (dfRobotGravitySensor.hasSensor()) {
|
||||
result = dfRobotGravitySensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (sht31Sensor.hasSensor()) {
|
||||
result = sht31Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
|
||||
@@ -99,44 +99,45 @@ bool PowerTelemetryModule::wantUIFrame()
|
||||
void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(x, y, "Power Telemetry");
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
if (lastMeasurementPacket == nullptr) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += _fontHeight(FONT_MEDIUM), "No measurement");
|
||||
// In case of no valid packet, display "Power Telemetry", "No measurement"
|
||||
display->drawString(x, y, "Power Telemetry");
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL), "No measurement");
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode the last power packet
|
||||
meshtastic_Telemetry lastMeasurement;
|
||||
|
||||
uint32_t agoSecs = service->GetTimeSinceMeshPacket(lastMeasurementPacket);
|
||||
const char *lastSender = getSenderShortName(*lastMeasurementPacket);
|
||||
|
||||
const meshtastic_Data &p = lastMeasurementPacket->decoded;
|
||||
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &lastMeasurement)) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += _fontHeight(FONT_MEDIUM), "Measurement Error");
|
||||
display->drawString(x, y, "Measurement Error");
|
||||
LOG_ERROR("Unable to decode last packet");
|
||||
return;
|
||||
}
|
||||
|
||||
// Display "Pow. From: ..."
|
||||
display->drawString(x, y, "Pow. From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
|
||||
|
||||
// Display current and voltage based on ...power_metrics.has_[channel/voltage/current]... flags
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += _fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
|
||||
if (lastMeasurement.variant.power_metrics.has_ch1_voltage || lastMeasurement.variant.power_metrics.has_ch1_current) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Ch1 Volt: " + String(lastMeasurement.variant.power_metrics.ch1_voltage, 2) +
|
||||
"V / Curr: " + String(lastMeasurement.variant.power_metrics.ch1_current, 0) + "mA");
|
||||
"Ch1: " + String(lastMeasurement.variant.power_metrics.ch1_voltage, 2) +
|
||||
"V " + String(lastMeasurement.variant.power_metrics.ch1_current, 0) + "mA");
|
||||
}
|
||||
if (lastMeasurement.variant.power_metrics.has_ch2_voltage || lastMeasurement.variant.power_metrics.has_ch2_current) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Ch2 Volt: " + String(lastMeasurement.variant.power_metrics.ch2_voltage, 2) +
|
||||
"V / Curr: " + String(lastMeasurement.variant.power_metrics.ch2_current, 0) + "mA");
|
||||
"Ch2: " + String(lastMeasurement.variant.power_metrics.ch2_voltage, 2) +
|
||||
"V " + String(lastMeasurement.variant.power_metrics.ch2_current, 0) + "mA");
|
||||
}
|
||||
if (lastMeasurement.variant.power_metrics.has_ch3_voltage || lastMeasurement.variant.power_metrics.has_ch3_current) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Ch3 Volt: " + String(lastMeasurement.variant.power_metrics.ch3_voltage, 2) +
|
||||
"V / Curr: " + String(lastMeasurement.variant.power_metrics.ch3_current, 0) + "mA");
|
||||
"Ch3: " + String(lastMeasurement.variant.power_metrics.ch3_voltage, 2) +
|
||||
"V " + String(lastMeasurement.variant.power_metrics.ch3_current, 0) + "mA");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "BME680Sensor.h"
|
||||
#include "FSCommon.h"
|
||||
#include "SPILock.h"
|
||||
#include "TelemetrySensor.h"
|
||||
|
||||
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
||||
@@ -75,6 +76,7 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
void BME680Sensor::loadState()
|
||||
{
|
||||
#ifdef FSCom
|
||||
spiLock->lock();
|
||||
auto file = FSCom.open(bsecConfigFileName, FILE_O_READ);
|
||||
if (file) {
|
||||
file.read((uint8_t *)&bsecState, BSEC_MAX_STATE_BLOB_SIZE);
|
||||
@@ -84,6 +86,7 @@ void BME680Sensor::loadState()
|
||||
} else {
|
||||
LOG_INFO("No %s state found (File: %s)", sensorName, bsecConfigFileName);
|
||||
}
|
||||
spiLock->unlock();
|
||||
#else
|
||||
LOG_ERROR("ERROR: Filesystem not implemented");
|
||||
#endif
|
||||
@@ -92,6 +95,7 @@ void BME680Sensor::loadState()
|
||||
void BME680Sensor::updateState()
|
||||
{
|
||||
#ifdef FSCom
|
||||
spiLock->lock();
|
||||
bool update = false;
|
||||
if (stateUpdateCounter == 0) {
|
||||
/* First state update when IAQ accuracy is >= 3 */
|
||||
@@ -127,6 +131,7 @@ void BME680Sensor::updateState()
|
||||
LOG_INFO("Can't write %s state (File: %s)", sensorName, bsecConfigFileName);
|
||||
}
|
||||
}
|
||||
spiLock->unlock();
|
||||
#else
|
||||
LOG_ERROR("ERROR: Filesystem not implemented");
|
||||
#endif
|
||||
|
||||
@@ -41,13 +41,12 @@ void CGRadSensSensor::begin(TwoWire *wire, uint8_t addr)
|
||||
float CGRadSensSensor::getStaticRadiation()
|
||||
{
|
||||
// Read a register, following the same pattern as the RCWL9620Sensor
|
||||
uint32_t data;
|
||||
_wire->beginTransmission(_addr); // Transfer data to addr.
|
||||
_wire->write(0x06); // Radiation intensity (static period T = 500 sec)
|
||||
if (_wire->endTransmission() == 0) {
|
||||
if (_wire->requestFrom(_addr, (uint8_t)3)) {
|
||||
; // Request 3 bytes
|
||||
data = _wire->read();
|
||||
uint32_t data = _wire->read();
|
||||
data <<= 8;
|
||||
data |= _wire->read();
|
||||
data <<= 8;
|
||||
|
||||
44
src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp
Normal file
44
src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "DFRobotGravitySensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <DFRobot_RainfallSensor.h>
|
||||
#include <string>
|
||||
|
||||
DFRobotGravitySensor::DFRobotGravitySensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DFROBOT_RAIN, "DFROBOT_RAIN") {}
|
||||
|
||||
int32_t DFRobotGravitySensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
gravity = DFRobot_RainfallSensor_I2C(nodeTelemetrySensorsMap[sensorType].second);
|
||||
status = gravity.begin();
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void DFRobotGravitySensor::setup()
|
||||
{
|
||||
LOG_DEBUG("%s VID: %x, PID: %x, Version: %s", sensorName, gravity.vid, gravity.pid, gravity.getFirmwareVersion().c_str());
|
||||
}
|
||||
|
||||
bool DFRobotGravitySensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_rainfall_1h = true;
|
||||
measurement->variant.environment_metrics.has_rainfall_24h = true;
|
||||
|
||||
measurement->variant.environment_metrics.rainfall_1h = gravity.getRainfall(1);
|
||||
measurement->variant.environment_metrics.rainfall_24h = gravity.getRainfall(24);
|
||||
|
||||
LOG_INFO("Rain 1h: %f mm", measurement->variant.environment_metrics.rainfall_1h);
|
||||
LOG_INFO("Rain 24h: %f mm", measurement->variant.environment_metrics.rainfall_24h);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
29
src/modules/Telemetry/Sensor/DFRobotGravitySensor.h
Normal file
29
src/modules/Telemetry/Sensor/DFRobotGravitySensor.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _MT_DFROBOTGRAVITYSENSOR_H
|
||||
#define _MT_DFROBOTGRAVITYSENSOR_H
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <DFRobot_RainfallSensor.h>
|
||||
#include <string>
|
||||
|
||||
class DFRobotGravitySensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
DFRobot_RainfallSensor_I2C gravity = DFRobot_RainfallSensor_I2C(nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
DFRobotGravitySensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
166
src/modules/Telemetry/Sensor/IndicatorSensor.cpp
Normal file
166
src/modules/Telemetry/Sensor/IndicatorSensor.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(SENSECAP_INDICATOR)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "IndicatorSensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "serialization/cobs.h"
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <driver/uart.h>
|
||||
|
||||
IndicatorSensor::IndicatorSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "Indicator") {}
|
||||
|
||||
#define SENSOR_BUF_SIZE (512)
|
||||
|
||||
uint8_t buf[SENSOR_BUF_SIZE]; // recv
|
||||
uint8_t data[SENSOR_BUF_SIZE]; // decode
|
||||
|
||||
#define ACK_PKT_PARA "ACK"
|
||||
|
||||
enum sensor_pkt_type {
|
||||
PKT_TYPE_ACK = 0x00, // uin32_t
|
||||
PKT_TYPE_CMD_COLLECT_INTERVAL = 0xA0, // uin32_t
|
||||
PKT_TYPE_CMD_BEEP_ON = 0xA1, // uin32_t ms: on time
|
||||
PKT_TYPE_CMD_BEEP_OFF = 0xA2,
|
||||
PKT_TYPE_CMD_SHUTDOWN = 0xA3, // uin32_t
|
||||
PKT_TYPE_CMD_POWER_ON = 0xA4,
|
||||
PKT_TYPE_SENSOR_SCD41_TEMP = 0xB0, // float
|
||||
PKT_TYPE_SENSOR_SCD41_HUMIDITY = 0xB1, // float
|
||||
PKT_TYPE_SENSOR_SCD41_CO2 = 0xB2, // float
|
||||
PKT_TYPE_SENSOR_AHT20_TEMP = 0xB3, // float
|
||||
PKT_TYPE_SENSOR_AHT20_HUMIDITY = 0xB4, // float
|
||||
PKT_TYPE_SENSOR_TVOC_INDEX = 0xB5, // float
|
||||
};
|
||||
|
||||
static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len)
|
||||
{
|
||||
uint8_t send_buf[32] = {0};
|
||||
uint8_t send_data[32] = {0};
|
||||
|
||||
if (len > 31) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t index = 1;
|
||||
|
||||
send_data[0] = cmd;
|
||||
|
||||
if (len > 0 && p_data != NULL) {
|
||||
memcpy(&send_data[1], p_data, len);
|
||||
index += len;
|
||||
}
|
||||
cobs_encode_result ret = cobs_encode(send_buf, sizeof(send_buf), send_data, index);
|
||||
|
||||
// LOG_DEBUG("cobs TX status:%d, len:%d, type 0x%x", ret.status, ret.out_len, cmd);
|
||||
|
||||
if (ret.status == COBS_ENCODE_OK) {
|
||||
return uart_write_bytes(SENSOR_PORT_NUM, send_buf, ret.out_len + 1);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t IndicatorSensor::runOnce()
|
||||
{
|
||||
LOG_INFO("%s: init", sensorName);
|
||||
setup();
|
||||
return 2 * DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; // give it some time to start up
|
||||
}
|
||||
|
||||
void IndicatorSensor::setup()
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = SENSOR_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
int intr_alloc_flags = 0;
|
||||
char buffer[11];
|
||||
|
||||
uart_driver_install(SENSOR_PORT_NUM, SENSOR_BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags);
|
||||
uart_param_config(SENSOR_PORT_NUM, &uart_config);
|
||||
uart_set_pin(SENSOR_PORT_NUM, SENSOR_RP2040_TXD, SENSOR_RP2040_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
cmd_send(PKT_TYPE_CMD_POWER_ON, NULL, 0);
|
||||
// measure and send only once every minute, for the phone API
|
||||
const char *interval = ultoa(60000, buffer, 10);
|
||||
cmd_send(PKT_TYPE_CMD_COLLECT_INTERVAL, interval, strlen(interval) + 1);
|
||||
}
|
||||
|
||||
bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
cobs_decode_result ret;
|
||||
int len = uart_read_bytes(SENSOR_PORT_NUM, buf, (SENSOR_BUF_SIZE - 1), 100 / portTICK_PERIOD_MS);
|
||||
|
||||
float value = 0.0;
|
||||
uint8_t *p_buf_start = buf;
|
||||
uint8_t *p_buf_end = buf;
|
||||
if (len > 0) {
|
||||
while (p_buf_start < (buf + len)) {
|
||||
p_buf_end = p_buf_start;
|
||||
while (p_buf_end < (buf + len)) {
|
||||
if (*p_buf_end == 0x00) {
|
||||
break;
|
||||
}
|
||||
p_buf_end++;
|
||||
}
|
||||
// decode buf
|
||||
memset(data, 0, sizeof(data));
|
||||
ret = cobs_decode(data, sizeof(data), p_buf_start, p_buf_end - p_buf_start);
|
||||
|
||||
// LOG_DEBUG("cobs RX status:%d, len:%d, type:0x%x ", ret.status, ret.out_len, data[0]);
|
||||
|
||||
if (ret.out_len > 1 && ret.status == COBS_DECODE_OK) {
|
||||
|
||||
value = 0.0;
|
||||
uint8_t pkt_type = data[0];
|
||||
switch (pkt_type) {
|
||||
case PKT_TYPE_SENSOR_SCD41_CO2: {
|
||||
memcpy(&value, &data[1], sizeof(value));
|
||||
// LOG_DEBUG("CO2: %.1f", value);
|
||||
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
case PKT_TYPE_SENSOR_AHT20_TEMP: {
|
||||
memcpy(&value, &data[1], sizeof(value));
|
||||
// LOG_DEBUG("Temp: %.1f", value);
|
||||
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
measurement->variant.environment_metrics.temperature = value;
|
||||
break;
|
||||
}
|
||||
|
||||
case PKT_TYPE_SENSOR_AHT20_HUMIDITY: {
|
||||
memcpy(&value, &data[1], sizeof(value));
|
||||
// LOG_DEBUG("Humidity: %.1f", value);
|
||||
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
|
||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
||||
measurement->variant.environment_metrics.relative_humidity = value;
|
||||
break;
|
||||
}
|
||||
|
||||
case PKT_TYPE_SENSOR_TVOC_INDEX: {
|
||||
memcpy(&value, &data[1], sizeof(value));
|
||||
// LOG_DEBUG("Tvoc: %.1f", value);
|
||||
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
|
||||
measurement->variant.environment_metrics.has_iaq = true;
|
||||
measurement->variant.environment_metrics.iaq = value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p_buf_start = p_buf_end + 1; // next message
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
19
src/modules/Telemetry/Sensor/IndicatorSensor.h
Normal file
19
src/modules/Telemetry/Sensor/IndicatorSensor.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
|
||||
class IndicatorSensor : public TelemetrySensor
|
||||
{
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
IndicatorSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "FSCommon.h"
|
||||
#include "NAU7802Sensor.h"
|
||||
#include "SPILock.h"
|
||||
#include "SafeFile.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Throttle.h>
|
||||
@@ -111,13 +112,16 @@ bool NAU7802Sensor::saveCalibrationData()
|
||||
} else {
|
||||
okay = true;
|
||||
}
|
||||
spiLock->lock();
|
||||
okay &= file.close();
|
||||
spiLock->unlock();
|
||||
|
||||
return okay;
|
||||
}
|
||||
|
||||
bool NAU7802Sensor::loadCalibrationData()
|
||||
{
|
||||
spiLock->lock();
|
||||
auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ);
|
||||
bool okay = false;
|
||||
if (file) {
|
||||
@@ -134,7 +138,8 @@ bool NAU7802Sensor::loadCalibrationData()
|
||||
} else {
|
||||
LOG_INFO("No %s state found (File: %s)", sensorName, nau7802ConfigFileName);
|
||||
}
|
||||
spiLock->unlock();
|
||||
return okay;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user