diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index 9c1dcf707..e31b026f4 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -1,24 +1,24 @@
version: 0.1
cli:
- version: 1.17.0
+ version: 1.17.1
plugins:
sources:
- id: trunk
- ref: v1.2.5
+ ref: v1.2.6
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- bandit@1.7.5
- - checkov@2.5.0
+ - checkov@3.0.16
- terrascan@1.18.3
- - trivy@0.45.1
- - trufflehog@3.59.0
+ - trivy@0.46.1
+ - trufflehog@3.62.1
- taplo@0.8.1
- - ruff@0.0.292
+ - ruff@0.1.3
- yamllint@1.32.0
- isort@5.12.0
- markdownlint@0.37.0
- - oxipng@8.0.0
+ - oxipng@9.0.0
- svgo@3.0.2
- actionlint@1.6.26
- flake8@6.1.0
@@ -30,15 +30,6 @@ lint:
- gitleaks@8.18.0
- clang-format@16.0.3
- prettier@3.0.3
- disabled:
- - taplo@0.8.1
- - shellcheck@0.9.0
- - shfmt@3.6.0
- - oxipng@8.0.0
- - actionlint@1.6.22
- - markdownlint@0.37.0
- - hadolint@2.12.0
- - svgo@3.0.2
runtimes:
enabled:
- python@3.10.8
diff --git a/platformio.ini b/platformio.ini
index a6ad6f873..cb79565f1 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -26,6 +26,7 @@
;default_envs = meshtastic-dr-dev
;default_envs = m5stack-coreink
;default_envs = rak4631
+;default_envs = rak10701
default_envs = wio-e5
extra_configs =
@@ -113,6 +114,7 @@ lib_deps =
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
boschsensortec/BME68x Sensor Library@^1.1.40407
adafruit/Adafruit MCP9808 Library@^2.0.0
+ https://github.com/Tinyu-Zhao/INA3221@^0.0.1
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0
adafruit/Adafruit SHTC3 Library@^1.0.0
diff --git a/protobufs b/protobufs
index 6290ee0f6..c845b7848 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit 6290ee0f6aa15939ee582c3c59bc7a048cc0478f
+Subproject commit c845b7848eebb11150ca0427773303bf8758e533
diff --git a/src/configuration.h b/src/configuration.h
index 2640b1572..199880c6b 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -111,6 +111,7 @@ along with this program. If not, see .
#define MCP9808_ADDR 0x18
#define INA_ADDR 0x40
#define INA_ADDR_ALTERNATE 0x41
+#define INA3221_ADDR 0x42
#define QMC6310_ADDR 0x1C
#define QMI8658_ADDR 0x6B
#define QMC5883L_ADDR 0x1E
@@ -187,6 +188,9 @@ along with this program. If not, see .
#ifndef HAS_TELEMETRY
#define HAS_TELEMETRY 0
#endif
+#ifndef HAS_SENSOR
+#define HAS_SENSOR 0
+#endif
#ifndef HAS_RADIO
#define HAS_RADIO 0
#endif
@@ -205,4 +209,4 @@ along with this program. If not, see .
#ifndef HW_VENDOR
#error HW_VENDOR must be defined
-#endif
\ No newline at end of file
+#endif
diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h
index 15d9b1342..2b4b8a735 100644
--- a/src/detect/ScanI2C.h
+++ b/src/detect/ScanI2C.h
@@ -25,6 +25,7 @@ class ScanI2C
BMP_280,
INA260,
INA219,
+ INA3221,
MCP9808,
SHT31,
SHTC3,
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index ced1e34dd..b3873dc91 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -251,7 +251,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
type = INA219;
}
break;
-
+ case INA3221_ADDR:
+ LOG_INFO("INA3221 sensor found at address 0x%x\n", (uint8_t)addr.address);
+ type = INA3221;
+ break;
case MCP9808_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
if (registerValue == 0x0400) {
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index ce5b18af8..47ba067d2 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -8,6 +8,7 @@
#ifdef ARCH_PORTDUINO
#include "meshUtils.h"
+#include
#endif
#ifndef GPS_RESET_MODE
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index d6fb7b5d3..554fa0aeb 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -390,7 +390,7 @@ class Screen : public concurrency::OSThread
SH1106Wire dispdev;
#elif defined(USE_SSD1306)
SSD1306Wire dispdev;
-#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
+#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
TFTDisplay dispdev;
#elif defined(USE_EINK)
EInkDisplay dispdev;
diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp
index 5eec2b200..63db8120a 100644
--- a/src/graphics/TFTDisplay.cpp
+++ b/src/graphics/TFTDisplay.cpp
@@ -105,6 +105,10 @@ class LGFX : public lgfx::LGFX_Device
static LGFX tft;
+#elif defined(RAK14014)
+#include
+TFT_eSPI tft = TFT_eSPI();
+
#elif defined(ST7789_CS)
#include // Graphics and font library for ST7735 driver chip
@@ -327,7 +331,7 @@ static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.
#endif
-#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER)
+#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014)
#include "SPILock.h"
#include "TFTDisplay.h"
#include
@@ -393,7 +397,9 @@ void TFTDisplay::sendCommand(uint8_t com)
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, LOW);
#endif
-#ifndef M5STACK
+
+#ifdef RAK14014
+#elif !defined(M5STACK)
tft.setBrightness(128);
#endif
break;
@@ -419,7 +425,8 @@ void TFTDisplay::sendCommand(uint8_t com)
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, HIGH);
#endif
-#ifndef M5STACK
+#ifdef RAK14014
+#elif !defined(M5STACK)
tft.setBrightness(0);
#endif
break;
@@ -441,7 +448,8 @@ void TFTDisplay::flipScreenVertically()
bool TFTDisplay::hasTouch(void)
{
-#ifndef M5STACK
+#ifdef RAK14014
+#elif !defined(M5STACK)
return tft.touch() != nullptr;
#else
return false;
@@ -450,7 +458,8 @@ bool TFTDisplay::hasTouch(void)
bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
{
-#ifndef M5STACK
+#ifdef RAK14014
+#elif !defined(M5STACK)
return tft.getTouch(x, y);
#else
return false;
@@ -471,6 +480,9 @@ bool TFTDisplay::connect()
#ifdef TFT_BL
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
pinMode(TFT_BL, OUTPUT);
+ // pinMode(PIN_3V3_EN, OUTPUT);
+ // digitalWrite(PIN_3V3_EN, HIGH);
+ LOG_INFO("Power to TFT Backlight\n");
#endif
#ifdef ST7735_BACKLIGHT_EN_V03
@@ -484,8 +496,13 @@ bool TFTDisplay::connect()
#endif
tft.init();
+
#if defined(M5STACK)
tft.setRotation(0);
+#elif defined(RAK14014)
+ tft.setRotation(1);
+ tft.setSwapBytes(true);
+// tft.fillScreen(TFT_BLACK);
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
tft.setRotation(1); // T-Deck has the TFT in landscape
#elif defined(T_WATCH_S3)
@@ -494,6 +511,7 @@ bool TFTDisplay::connect()
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
#endif
tft.fillScreen(TFT_BLACK);
+
return true;
}
diff --git a/src/main.cpp b/src/main.cpp
index 0faaa0575..6b84af084 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -67,6 +67,13 @@ NRF52Bluetooth *nrf52Bluetooth;
#include "platform/portduino/SimRadio.h"
#endif
+#ifdef ARCH_RASPBERRY_PI
+#include "platform/portduino/PiHal.h"
+#include
+#include
+#include
+#endif
+
#if HAS_BUTTON
#include "ButtonThread.h"
#endif
@@ -128,12 +135,32 @@ std::pair nodeTelemetrySensorsMap[_meshtastic_TelemetrySenso
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
+#ifdef ARCH_RASPBERRY_PI
+void getPiMacAddr(uint8_t *dmac)
+{
+ std::fstream macIdentity;
+ macIdentity.open("/sys/kernel/debug/bluetooth/hci0/identity", std::ios::in);
+ std::string macLine;
+ getline(macIdentity, macLine);
+ macIdentity.close();
+
+ dmac[0] = strtol(macLine.substr(0, 2).c_str(), NULL, 16);
+ dmac[1] = strtol(macLine.substr(3, 2).c_str(), NULL, 16);
+ dmac[2] = strtol(macLine.substr(6, 2).c_str(), NULL, 16);
+ dmac[3] = strtol(macLine.substr(9, 2).c_str(), NULL, 16);
+ dmac[4] = strtol(macLine.substr(12, 2).c_str(), NULL, 16);
+ dmac[5] = strtol(macLine.substr(15, 2).c_str(), NULL, 16);
+}
+#endif
+
const char *getDeviceName()
{
uint8_t dmac[6];
-
+#ifdef ARCH_RASPBERRY_PI
+ getPiMacAddr(dmac);
+#else
getMacAddr(dmac);
-
+#endif
// Meshtastic_ab3c or Shortname_abcd
static char name[20];
snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]);
@@ -502,6 +529,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31)
@@ -664,7 +692,20 @@ void setup()
digitalWrite(SX126X_ANT_SW, 1);
#endif
-#ifdef HW_SPI1_DEVICE
+#ifdef ARCH_RASPBERRY_PI
+ PiHal *RadioLibHAL = new PiHal(1);
+ if (!rIf) {
+ rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, 21, 16, 18, 20);
+ if (!rIf->init()) {
+ LOG_WARN("Failed to find SX1262 radio\n");
+ delete rIf;
+ rIf = NULL;
+ } else {
+ LOG_INFO("SX1262 Radio init succeeded, using SX1262 radio\n");
+ }
+ }
+
+#elif defined(HW_SPI1_DEVICE)
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
#else // HW_SPI1_DEVICE
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
@@ -710,7 +751,7 @@ void setup()
}
#endif
-#if defined(USE_SX1262)
+#if defined(USE_SX1262) && !defined(ARCH_RASPBERRY_PI)
if (!rIf) {
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
if (!rIf->init()) {
diff --git a/src/main.h b/src/main.h
index 3f0120406..5c9de1b81 100644
--- a/src/main.h
+++ b/src/main.h
@@ -56,6 +56,7 @@ extern graphics::Screen *screen;
// Return a human readable string of the form "Meshtastic_ab13"
const char *getDeviceName();
+void getPiMacAddr(uint8_t *dmac);
extern uint32_t timeLastPowered;
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 0fe0b7f2b..fe38a9bfe 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -323,6 +323,20 @@ void NodeDB::resetNodes()
neighborInfoModule->resetNeighbors();
}
+void NodeDB::removeNodeByNum(uint nodeNum)
+{
+ int newPos = 0, removed = 0;
+ for (int i = 0; i < *numMeshNodes; i++) {
+ if (meshNodes[i].num != nodeNum)
+ meshNodes[newPos++] = meshNodes[i];
+ else
+ removed++;
+ }
+ *numMeshNodes -= removed;
+ LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Saving changes...\n", removed);
+ saveDeviceStateToDisk();
+}
+
void NodeDB::cleanupMeshDB()
{
int newPos = 0, removed = 0;
@@ -421,7 +435,11 @@ void NodeDB::init()
*/
void NodeDB::pickNewNodeNum()
{
+#ifdef ARCH_RASPBERRY_PI
+ getPiMacAddr(ourMacAddr); // Make sure ourMacAddr is set
+#else
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
+#endif
// Pick an initial nodenum based on the macaddr
NodeNum nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
@@ -433,6 +451,7 @@ void NodeDB::pickNewNodeNum()
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate);
nodeNum = candidate;
}
+ LOG_WARN("Using nodenum 0x%x \n", nodeNum);
myNodeInfo.my_node_num = nodeNum;
}
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index e2472f182..d706552d7 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -111,7 +111,7 @@ class NodeDB
/// Return the number of nodes we've heard from recently (within the last 2 hrs?)
size_t getNumOnlineMeshNodes();
- void initConfigIntervals(), initModuleConfigIntervals(), resetNodes();
+ void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(), removeNodeByNum(uint nodeNum);
bool factoryReset();
diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h
index e59acca8f..89d237a02 100644
--- a/src/mesh/PacketHistory.h
+++ b/src/mesh/PacketHistory.h
@@ -3,8 +3,8 @@
#include "Router.h"
#include
-/// We clear our old flood record five minute after we see the last of it
-#define FLOOD_EXPIRE_TIME (5 * 60 * 1000L)
+/// We clear our old flood record 10 minutes after we see the last of it
+#define FLOOD_EXPIRE_TIME (10 * 60 * 1000L)
/**
* A record of a recent message broadcast
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index 5abcc8a31..a01647bfa 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -294,6 +294,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor;
break;
+ case meshtastic_ModuleConfig_ambient_lighting_tag:
+ fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag;
+ fromRadioScratch.moduleConfig.payload_variant.ambient_lighting = moduleConfig.ambient_lighting;
+ break;
default:
LOG_ERROR("Unknown module config type %d\n", config_state);
}
diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp
index 3102aa029..d7f319f8e 100644
--- a/src/mesh/RF95Interface.cpp
+++ b/src/mesh/RF95Interface.cpp
@@ -37,9 +37,6 @@ bool RF95Interface::init()
{
RadioLibInterface::init();
- if (power == 0)
- power = POWER_DEFAULT;
-
if (power > MAX_POWER) // This chip has lower power limits than some
power = MAX_POWER;
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index e128377e3..b2ce489ff 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -384,27 +384,27 @@ void RadioInterface::applyModemConfig()
switch (loraConfig.modem_preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250;
- cr = 8;
+ cr = 5;
sf = 7;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250;
- cr = 8;
+ cr = 5;
sf = 8;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
bw = (myRegion->wideLora) ? 812.5 : 250;
- cr = 8;
+ cr = 5;
sf = 9;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
bw = (myRegion->wideLora) ? 812.5 : 250;
- cr = 8;
+ cr = 5;
sf = 10;
break;
default: // Config_LoRaConfig_ModemPreset_LONG_FAST is default. Gracefully use this is preset is something illegal.
bw = (myRegion->wideLora) ? 812.5 : 250;
- cr = 8;
+ cr = 5;
sf = 11;
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
@@ -448,7 +448,9 @@ void RadioInterface::applyModemConfig()
power = myRegion->powerLimit;
if (power == 0)
- power = 17; // Default to default power if we don't have a valid power
+ power = 17; // Default to this power level if we don't have a valid regional power limit (powerLimit of myRegion defaults
+ // to 0, currently no region has an actual power limit of 0 [dBm] so we can assume regions which have this
+ // variable set to 0 don't have a valid power limit)
// Set final tx_power back onto config
loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger
diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h
index fad5ea1d1..60d7be4ea 100644
--- a/src/mesh/RadioInterface.h
+++ b/src/mesh/RadioInterface.h
@@ -64,7 +64,7 @@ class RadioInterface
float bw = 125;
uint8_t sf = 9;
- uint8_t cr = 7;
+ uint8_t cr = 5;
/** Slottime is the minimum time to wait, consisting of:
- CAD duration (maximum of SX126x and SX127x);
- roundtrip air propagation time (assuming max. 30km between nodes);
diff --git a/src/mesh/STM32WLE5JCInterface.cpp b/src/mesh/STM32WLE5JCInterface.cpp
index 5b6fd0844..3c1870d3b 100644
--- a/src/mesh/STM32WLE5JCInterface.cpp
+++ b/src/mesh/STM32WLE5JCInterface.cpp
@@ -20,9 +20,6 @@ bool STM32WLE5JCInterface::init()
lora.setRfSwitchTable(rfswitch_pins, rfswitch_table);
- if (power == 0)
- power = STM32WLx_MAX_POWER;
-
if (power > STM32WLx_MAX_POWER) // This chip has lower power limits than some
power = STM32WLx_MAX_POWER;
diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp
index 0e94bff93..980107917 100644
--- a/src/mesh/SX126xInterface.cpp
+++ b/src/mesh/SX126xInterface.cpp
@@ -43,6 +43,7 @@ template bool SX126xInterface::init()
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
RadioLibInterface::init();
+
if (power > SX126X_MAX_POWER) // Clamp power to maximum defined level
power = SX126X_MAX_POWER;
diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp
index f056f7369..1916c8042 100644
--- a/src/mesh/SX128xInterface.cpp
+++ b/src/mesh/SX128xInterface.cpp
@@ -42,9 +42,6 @@ template bool SX128xInterface::init()
RadioLibInterface::init();
- if (power == 0)
- power = SX128X_MAX_POWER;
-
if (power > SX128X_MAX_POWER) // This chip has lower power limits than some
power = SX128X_MAX_POWER;
diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h
index 38248d94a..9978c5591 100644
--- a/src/mesh/generated/meshtastic/admin.pb.h
+++ b/src/mesh/generated/meshtastic/admin.pb.h
@@ -145,6 +145,8 @@ typedef struct _meshtastic_AdminMessage {
char set_canned_message_module_messages[201];
/* Set the ringtone for ExternalNotification. */
char set_ringtone_message[231];
+ /* Remove the node by the specified node-num from the NodeDB on the device */
+ uint32_t remove_by_nodenum;
/* Begins an edit transaction for config, module config, owner, and channel settings changes
This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */
bool begin_edit_settings;
@@ -226,6 +228,7 @@ extern "C" {
#define meshtastic_AdminMessage_set_module_config_tag 35
#define meshtastic_AdminMessage_set_canned_message_module_messages_tag 36
#define meshtastic_AdminMessage_set_ringtone_message_tag 37
+#define meshtastic_AdminMessage_remove_by_nodenum_tag 38
#define meshtastic_AdminMessage_begin_edit_settings_tag 64
#define meshtastic_AdminMessage_commit_edit_settings_tag 65
#define meshtastic_AdminMessage_reboot_ota_seconds_tag 95
@@ -262,6 +265,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34)
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_module_config,set_module_config), 35) \
X(a, STATIC, ONEOF, STRING, (payload_variant,set_canned_message_module_messages,set_canned_message_module_messages), 36) \
X(a, STATIC, ONEOF, STRING, (payload_variant,set_ringtone_message,set_ringtone_message), 37) \
+X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_by_nodenum,remove_by_nodenum), 38) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \
diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h
index 3ad1bf5a0..29158733a 100644
--- a/src/mesh/generated/meshtastic/config.pb.h
+++ b/src/mesh/generated/meshtastic/config.pb.h
@@ -341,7 +341,7 @@ typedef struct _meshtastic_Config_NetworkConfig {
acquire an address via DHCP */
char wifi_ssid[33];
/* If set, will be use to authenticate to the named wifi */
- char wifi_psk[64];
+ char wifi_psk[65];
/* NTP server to use if WiFi is conneced, defaults to `0.pool.ntp.org` */
char ntp_server[33];
/* Enable Ethernet */
@@ -792,10 +792,10 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
#define meshtastic_Config_DisplayConfig_size 28
#define meshtastic_Config_LoRaConfig_size 79
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
-#define meshtastic_Config_NetworkConfig_size 195
+#define meshtastic_Config_NetworkConfig_size 196
#define meshtastic_Config_PositionConfig_size 60
#define meshtastic_Config_PowerConfig_size 40
-#define meshtastic_Config_size 198
+#define meshtastic_Config_size 199
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h
index 0a324e107..c0e747f81 100644
--- a/src/mesh/generated/meshtastic/deviceonly.pb.h
+++ b/src/mesh/generated/meshtastic/deviceonly.pb.h
@@ -320,7 +320,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
#define meshtastic_DeviceState_size 17193
#define meshtastic_NodeInfoLite_size 154
#define meshtastic_NodeRemoteHardwarePin_size 29
-#define meshtastic_OEMStore_size 3220
+#define meshtastic_OEMStore_size 3231
#define meshtastic_PositionLite_size 28
#ifdef __cplusplus
diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h
index 44c49d047..9d3e63eee 100644
--- a/src/mesh/generated/meshtastic/localonly.pb.h
+++ b/src/mesh/generated/meshtastic/localonly.pb.h
@@ -175,7 +175,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_LocalConfig_size 465
-#define meshtastic_LocalModuleConfig_size 609
+#define meshtastic_LocalModuleConfig_size 621
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h
index 28a11ffcd..b9f43e352 100644
--- a/src/mesh/generated/meshtastic/module_config.pb.h
+++ b/src/mesh/generated/meshtastic/module_config.pb.h
@@ -232,6 +232,9 @@ typedef struct _meshtastic_ModuleConfig_ExternalNotificationConfig {
Default is 0 which means don't repeat at all. 60 would mean blink
and/or beep for 60 seconds */
uint16_t nag_timeout;
+ /* When true, enables devices with native I2S audio output to use the RTTTL over speaker like a buzzer
+ T-Watch S3 and T-Deck for example have this capability */
+ bool use_i2s_as_buzzer;
} meshtastic_ModuleConfig_ExternalNotificationConfig;
/* Store and Forward Module Config */
@@ -278,6 +281,15 @@ typedef struct _meshtastic_ModuleConfig_TelemetryConfig {
/* Interval in seconds of how often we should try to send our
air quality metrics to the mesh */
uint32_t air_quality_interval;
+ /* Interval in seconds of how often we should try to send our
+ air quality metrics to the mesh */
+ bool power_measurement_enabled;
+ /* Interval in seconds of how often we should try to send our
+ air quality metrics to the mesh */
+ uint32_t power_update_interval;
+ /* Interval in seconds of how often we should try to send our
+ air quality metrics to the mesh */
+ bool power_screen_enabled;
} meshtastic_ModuleConfig_TelemetryConfig;
/* TODO: REPLACE */
@@ -431,10 +443,10 @@ extern "C" {
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_default {0, 0, 0, 0, "", 0, 0, 0}
#define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
-#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
-#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0}
+#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN}
@@ -445,10 +457,10 @@ extern "C" {
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_zero {0, 0, 0, 0, "", 0, 0, 0}
#define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
-#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
-#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
+#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN}
@@ -502,6 +514,7 @@ extern "C" {
#define meshtastic_ModuleConfig_ExternalNotificationConfig_alert_bell_vibra_tag 12
#define meshtastic_ModuleConfig_ExternalNotificationConfig_alert_bell_buzzer_tag 13
#define meshtastic_ModuleConfig_ExternalNotificationConfig_nag_timeout_tag 14
+#define meshtastic_ModuleConfig_ExternalNotificationConfig_use_i2s_as_buzzer_tag 15
#define meshtastic_ModuleConfig_StoreForwardConfig_enabled_tag 1
#define meshtastic_ModuleConfig_StoreForwardConfig_heartbeat_tag 2
#define meshtastic_ModuleConfig_StoreForwardConfig_records_tag 3
@@ -517,6 +530,9 @@ extern "C" {
#define meshtastic_ModuleConfig_TelemetryConfig_environment_display_fahrenheit_tag 5
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_enabled_tag 6
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_interval_tag 7
+#define meshtastic_ModuleConfig_TelemetryConfig_power_measurement_enabled_tag 8
+#define meshtastic_ModuleConfig_TelemetryConfig_power_update_interval_tag 9
+#define meshtastic_ModuleConfig_TelemetryConfig_power_screen_enabled_tag 10
#define meshtastic_ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3
@@ -657,7 +673,8 @@ X(a, STATIC, SINGULAR, BOOL, alert_message_vibra, 10) \
X(a, STATIC, SINGULAR, BOOL, alert_message_buzzer, 11) \
X(a, STATIC, SINGULAR, BOOL, alert_bell_vibra, 12) \
X(a, STATIC, SINGULAR, BOOL, alert_bell_buzzer, 13) \
-X(a, STATIC, SINGULAR, UINT32, nag_timeout, 14)
+X(a, STATIC, SINGULAR, UINT32, nag_timeout, 14) \
+X(a, STATIC, SINGULAR, BOOL, use_i2s_as_buzzer, 15)
#define meshtastic_ModuleConfig_ExternalNotificationConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_ExternalNotificationConfig_DEFAULT NULL
@@ -684,7 +701,10 @@ X(a, STATIC, SINGULAR, BOOL, environment_measurement_enabled, 3) \
X(a, STATIC, SINGULAR, BOOL, environment_screen_enabled, 4) \
X(a, STATIC, SINGULAR, BOOL, environment_display_fahrenheit, 5) \
X(a, STATIC, SINGULAR, BOOL, air_quality_enabled, 6) \
-X(a, STATIC, SINGULAR, UINT32, air_quality_interval, 7)
+X(a, STATIC, SINGULAR, UINT32, air_quality_interval, 7) \
+X(a, STATIC, SINGULAR, BOOL, power_measurement_enabled, 8) \
+X(a, STATIC, SINGULAR, UINT32, power_update_interval, 9) \
+X(a, STATIC, SINGULAR, BOOL, power_screen_enabled, 10)
#define meshtastic_ModuleConfig_TelemetryConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_TelemetryConfig_DEFAULT NULL
@@ -755,14 +775,14 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
#define meshtastic_ModuleConfig_AudioConfig_size 19
#define meshtastic_ModuleConfig_CannedMessageConfig_size 49
#define meshtastic_ModuleConfig_DetectionSensorConfig_size 44
-#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40
+#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 42
#define meshtastic_ModuleConfig_MQTTConfig_size 222
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8
#define meshtastic_ModuleConfig_RangeTestConfig_size 10
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
#define meshtastic_ModuleConfig_SerialConfig_size 28
#define meshtastic_ModuleConfig_StoreForwardConfig_size 22
-#define meshtastic_ModuleConfig_TelemetryConfig_size 26
+#define meshtastic_ModuleConfig_TelemetryConfig_size 36
#define meshtastic_ModuleConfig_size 225
#define meshtastic_RemoteHardwarePin_size 21
diff --git a/src/mesh/generated/meshtastic/telemetry.pb.c b/src/mesh/generated/meshtastic/telemetry.pb.c
index cbcac3e20..046998ae9 100644
--- a/src/mesh/generated/meshtastic/telemetry.pb.c
+++ b/src/mesh/generated/meshtastic/telemetry.pb.c
@@ -12,6 +12,9 @@ PB_BIND(meshtastic_DeviceMetrics, meshtastic_DeviceMetrics, AUTO)
PB_BIND(meshtastic_EnvironmentMetrics, meshtastic_EnvironmentMetrics, AUTO)
+PB_BIND(meshtastic_PowerMetrics, meshtastic_PowerMetrics, AUTO)
+
+
PB_BIND(meshtastic_AirQualityMetrics, meshtastic_AirQualityMetrics, AUTO)
diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h
index 760286598..fc2780a96 100644
--- a/src/mesh/generated/meshtastic/telemetry.pb.h
+++ b/src/mesh/generated/meshtastic/telemetry.pb.h
@@ -39,7 +39,9 @@ typedef enum _meshtastic_TelemetrySensorType {
/* High accuracy temperature and humidity */
meshtastic_TelemetrySensorType_SHT31 = 12,
/* PM2.5 air quality sensor */
- meshtastic_TelemetrySensorType_PMSA003I = 13
+ meshtastic_TelemetrySensorType_PMSA003I = 13,
+ /* INA3221 3 Channel Voltage / Current Sensor */
+ meshtastic_TelemetrySensorType_INA3221 = 14
} meshtastic_TelemetrySensorType;
/* Struct definitions */
@@ -65,12 +67,28 @@ typedef struct _meshtastic_EnvironmentMetrics {
float barometric_pressure;
/* Gas resistance in MOhm measured */
float gas_resistance;
- /* Voltage measured */
+ /* Voltage measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) */
float voltage;
- /* Current measured */
+ /* Current measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) */
float current;
} meshtastic_EnvironmentMetrics;
+/* Power Metrics (voltage / current / etc) */
+typedef struct _meshtastic_PowerMetrics {
+ /* Voltage (Ch1) */
+ float ch1_voltage;
+ /* Current (Ch1) */
+ float ch1_current;
+ /* Voltage (Ch2) */
+ float ch2_voltage;
+ /* Current (Ch2) */
+ float ch2_current;
+ /* Voltage (Ch3) */
+ float ch3_voltage;
+ /* Current (Ch3) */
+ float ch3_current;
+} meshtastic_PowerMetrics;
+
/* Air quality metrics */
typedef struct _meshtastic_AirQualityMetrics {
/* Concentration Units Standard PM1.0 */
@@ -111,6 +129,8 @@ typedef struct _meshtastic_Telemetry {
meshtastic_EnvironmentMetrics environment_metrics;
/* Air quality metrics */
meshtastic_AirQualityMetrics air_quality_metrics;
+ /* Power Metrics */
+ meshtastic_PowerMetrics power_metrics;
} variant;
} meshtastic_Telemetry;
@@ -121,8 +141,9 @@ extern "C" {
/* Helper constants for enums */
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
-#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_PMSA003I
-#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_PMSA003I+1))
+#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_INA3221
+#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_INA3221+1))
+
@@ -132,10 +153,12 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0}
#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0}
+#define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0}
#define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}}
#define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0}
#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0}
+#define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0}
#define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}}
@@ -150,6 +173,12 @@ extern "C" {
#define meshtastic_EnvironmentMetrics_gas_resistance_tag 4
#define meshtastic_EnvironmentMetrics_voltage_tag 5
#define meshtastic_EnvironmentMetrics_current_tag 6
+#define meshtastic_PowerMetrics_ch1_voltage_tag 1
+#define meshtastic_PowerMetrics_ch1_current_tag 2
+#define meshtastic_PowerMetrics_ch2_voltage_tag 3
+#define meshtastic_PowerMetrics_ch2_current_tag 4
+#define meshtastic_PowerMetrics_ch3_voltage_tag 5
+#define meshtastic_PowerMetrics_ch3_current_tag 6
#define meshtastic_AirQualityMetrics_pm10_standard_tag 1
#define meshtastic_AirQualityMetrics_pm25_standard_tag 2
#define meshtastic_AirQualityMetrics_pm100_standard_tag 3
@@ -166,6 +195,7 @@ extern "C" {
#define meshtastic_Telemetry_device_metrics_tag 2
#define meshtastic_Telemetry_environment_metrics_tag 3
#define meshtastic_Telemetry_air_quality_metrics_tag 4
+#define meshtastic_Telemetry_power_metrics_tag 5
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceMetrics_FIELDLIST(X, a) \
@@ -186,6 +216,16 @@ X(a, STATIC, SINGULAR, FLOAT, current, 6)
#define meshtastic_EnvironmentMetrics_CALLBACK NULL
#define meshtastic_EnvironmentMetrics_DEFAULT NULL
+#define meshtastic_PowerMetrics_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, FLOAT, ch1_voltage, 1) \
+X(a, STATIC, SINGULAR, FLOAT, ch1_current, 2) \
+X(a, STATIC, SINGULAR, FLOAT, ch2_voltage, 3) \
+X(a, STATIC, SINGULAR, FLOAT, ch2_current, 4) \
+X(a, STATIC, SINGULAR, FLOAT, ch3_voltage, 5) \
+X(a, STATIC, SINGULAR, FLOAT, ch3_current, 6)
+#define meshtastic_PowerMetrics_CALLBACK NULL
+#define meshtastic_PowerMetrics_DEFAULT NULL
+
#define meshtastic_AirQualityMetrics_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, pm10_standard, 1) \
X(a, STATIC, SINGULAR, UINT32, pm25_standard, 2) \
@@ -206,21 +246,25 @@ X(a, STATIC, SINGULAR, UINT32, particles_100um, 12)
X(a, STATIC, SINGULAR, FIXED32, time, 1) \
X(a, STATIC, ONEOF, MESSAGE, (variant,device_metrics,variant.device_metrics), 2) \
X(a, STATIC, ONEOF, MESSAGE, (variant,environment_metrics,variant.environment_metrics), 3) \
-X(a, STATIC, ONEOF, MESSAGE, (variant,air_quality_metrics,variant.air_quality_metrics), 4)
+X(a, STATIC, ONEOF, MESSAGE, (variant,air_quality_metrics,variant.air_quality_metrics), 4) \
+X(a, STATIC, ONEOF, MESSAGE, (variant,power_metrics,variant.power_metrics), 5)
#define meshtastic_Telemetry_CALLBACK NULL
#define meshtastic_Telemetry_DEFAULT NULL
#define meshtastic_Telemetry_variant_device_metrics_MSGTYPE meshtastic_DeviceMetrics
#define meshtastic_Telemetry_variant_environment_metrics_MSGTYPE meshtastic_EnvironmentMetrics
#define meshtastic_Telemetry_variant_air_quality_metrics_MSGTYPE meshtastic_AirQualityMetrics
+#define meshtastic_Telemetry_variant_power_metrics_MSGTYPE meshtastic_PowerMetrics
extern const pb_msgdesc_t meshtastic_DeviceMetrics_msg;
extern const pb_msgdesc_t meshtastic_EnvironmentMetrics_msg;
+extern const pb_msgdesc_t meshtastic_PowerMetrics_msg;
extern const pb_msgdesc_t meshtastic_AirQualityMetrics_msg;
extern const pb_msgdesc_t meshtastic_Telemetry_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_DeviceMetrics_fields &meshtastic_DeviceMetrics_msg
#define meshtastic_EnvironmentMetrics_fields &meshtastic_EnvironmentMetrics_msg
+#define meshtastic_PowerMetrics_fields &meshtastic_PowerMetrics_msg
#define meshtastic_AirQualityMetrics_fields &meshtastic_AirQualityMetrics_msg
#define meshtastic_Telemetry_fields &meshtastic_Telemetry_msg
@@ -228,6 +272,7 @@ extern const pb_msgdesc_t meshtastic_Telemetry_msg;
#define meshtastic_AirQualityMetrics_size 72
#define meshtastic_DeviceMetrics_size 21
#define meshtastic_EnvironmentMetrics_size 30
+#define meshtastic_PowerMetrics_size 30
#define meshtastic_Telemetry_size 79
#ifdef __cplusplus
diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp
index c54366f04..2ea2a76a5 100644
--- a/src/mesh/http/ContentHandler.cpp
+++ b/src/mesh/http/ContentHandler.cpp
@@ -144,8 +144,8 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res)
/*
For documentation, see:
- https://meshtastic.org/docs/developers/device/http-api
- https://meshtastic.org/docs/developers/device/device-api
+ https://meshtastic.org/docs/development/device/http-api
+ https://meshtastic.org/docs/development/device/client-api
*/
// Get access to the parameters
@@ -194,8 +194,8 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
/*
For documentation, see:
- https://meshtastic.org/docs/developers/device/http-api
- https://meshtastic.org/docs/developers/device/device-api
+ https://meshtastic.org/docs/development/device/http-api
+ https://meshtastic.org/docs/development/device/client-api
*/
res->setHeader("Content-Type", "application/x-protobuf");
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index f25e8db33..dce33ad48 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -182,6 +182,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
}
break;
}
+ case meshtastic_AdminMessage_remove_by_nodenum_tag: {
+ LOG_INFO("Client is receiving a remove_nodenum command.\n");
+ nodeDB.removeNodeByNum(r->remove_by_nodenum);
+ reboot(DEFAULT_REBOOT_SECONDS);
+ break;
+ }
#ifdef ARCH_PORTDUINO
case meshtastic_AdminMessage_exit_simulator_tag:
LOG_INFO("Exiting simulator\n");
@@ -378,6 +384,11 @@ void AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
moduleConfig.has_detection_sensor = true;
moduleConfig.detection_sensor = c.payload_variant.detection_sensor;
break;
+ case meshtastic_ModuleConfig_ambient_lighting_tag:
+ LOG_INFO("Setting module config: Ambient Lighting\n");
+ moduleConfig.has_ambient_lighting = true;
+ moduleConfig.ambient_lighting = c.payload_variant.ambient_lighting;
+ break;
}
saveChanges(SEGMENT_MODULECONFIG);
@@ -523,6 +534,11 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
res.get_module_config_response.payload_variant.detection_sensor = moduleConfig.detection_sensor;
break;
+ case meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG:
+ LOG_INFO("Getting module config: Ambient Lighting\n");
+ res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag;
+ res.get_module_config_response.payload_variant.ambient_lighting = moduleConfig.ambient_lighting;
+ break;
}
// NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.
diff --git a/src/modules/DetectionSensorModule.cpp b/src/modules/DetectionSensorModule.cpp
index f1fc26244..6c35e94ae 100644
--- a/src/modules/DetectionSensorModule.cpp
+++ b/src/modules/DetectionSensorModule.cpp
@@ -28,6 +28,12 @@ int32_t DetectionSensorModule::runOnce()
return disable();
if (firstTime) {
+
+#ifdef DETECTION_SENSOR_EN
+ pinMode(DETECTION_SENSOR_EN, OUTPUT);
+ digitalWrite(DETECTION_SENSOR_EN, HIGH);
+#endif
+
// This is the first time the OSThread library has called this function, so do some setup
firstTime = false;
if (moduleConfig.detection_sensor.monitor_pin > 0) {
diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp
index 1e0e8250d..6a7641b04 100644
--- a/src/modules/ExternalNotificationModule.cpp
+++ b/src/modules/ExternalNotificationModule.cpp
@@ -8,7 +8,7 @@
* handle the module's behavior.
*
* Documentation:
- * https://meshtastic.org/docs/settings/moduleconfig/external-notification
+ * https://meshtastic.org/docs/configuration/module/external-notification
*
* @author Jm Casler & Meshtastic Team
* @date [Insert Date]
@@ -31,6 +31,10 @@
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
+uint8_t colorState = 1;
+uint8_t brightnessIndex = 0;
+uint8_t brightnessValues[] = {0, 10, 20, 30, 50, 90, 160, 170}; // blue gets multiplied by 1.5
+bool ascending = true;
#endif
#ifndef PIN_BUZZER
@@ -39,7 +43,7 @@ uint8_t blue = 0;
/*
Documentation:
- https://meshtastic.org/docs/settings/moduleconfig/external-notification
+ https://meshtastic.org/docs/configuration/module/external-notification
*/
// Default configurations
@@ -100,11 +104,26 @@ int32_t ExternalNotificationModule::runOnce()
}
#ifdef HAS_NCP5623
if (rgb_found.type == ScanI2C::NCP5623) {
- green = (green + 50) % 255;
- red = abs(red - green) % 255;
- blue = abs(blue / red) % 255;
-
+ red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
+ green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7
+ blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7
rgb.setColor(red, green, blue);
+
+ if (ascending) { // fade in
+ brightnessIndex++;
+ if (brightnessIndex == (sizeof(brightnessValues) - 1)) {
+ ascending = false;
+ }
+ } else {
+ brightnessIndex--; // fade out
+ }
+ if (brightnessIndex == 0) {
+ ascending = true;
+ colorState++; // next color
+ if (colorState > 7) {
+ colorState = 1;
+ }
+ }
}
#endif
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index 4c3d7eb61..526a1c7d8 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -24,6 +24,9 @@
#include "modules/Telemetry/AirQualityTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h"
#endif
+#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
+#include "modules/Telemetry/PowerTelemetry.h"
+#endif
#ifdef ARCH_ESP32
#include "modules/esp32/AudioModule.h"
#include "modules/esp32/StoreForwardModule.h"
@@ -92,6 +95,9 @@ void setupModules()
new AirQualityTelemetryModule();
}
#endif
+#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
+ new PowerTelemetryModule();
+#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
!defined(CONFIG_IDF_TARGET_ESP32C3)
new SerialModule();
diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp
new file mode 100644
index 000000000..53e26ee6a
--- /dev/null
+++ b/src/modules/Telemetry/PowerTelemetry.cpp
@@ -0,0 +1,240 @@
+#include "PowerTelemetry.h"
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "MeshService.h"
+#include "NodeDB.h"
+#include "PowerFSM.h"
+#include "RTC.h"
+#include "Router.h"
+#include "configuration.h"
+#include "main.h"
+#include "power.h"
+#include "sleep.h"
+#include "target_specific.h"
+
+#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
+#include "Sensor/INA3221Sensor.h"
+INA3221Sensor ina3221Sensor;
+#endif
+
+#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
+#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
+
+#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
+ !defined(DISPLAY_FORCE_SMALL_FONTS)
+
+// 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 PowerTelemetryModule::runOnce()
+{
+ if (sleepOnNextExecution == true) {
+ sleepOnNextExecution = false;
+ uint32_t nightyNightMs = getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval);
+ LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs);
+ doDeepSleep(nightyNightMs, true);
+ }
+
+ uint32_t result = UINT32_MAX;
+ /*
+ Uncomment the preferences below if you want to use the module
+ without having to configure it from the PythonAPI or WebUI.
+ */
+
+ // moduleConfig.telemetry.power_measurement_enabled = 1;
+ // moduleConfig.telemetry.power_screen_enabled = 1;
+ // moduleConfig.telemetry.power_update_interval = 45;
+
+ if (!(moduleConfig.telemetry.power_measurement_enabled)) {
+ // If this module is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
+ return disable();
+ }
+
+ if (firstTime) {
+ // This is the first time the OSThread library has called this function, so do some setup
+ firstTime = 0;
+#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
+ if (moduleConfig.telemetry.power_measurement_enabled) {
+ LOG_INFO("Power Telemetry: Initializing\n");
+ // 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
+ if (ina219Sensor.hasSensor() && !ina219Sensor.isInitialized())
+ result = ina219Sensor.runOnce();
+ if (ina260Sensor.hasSensor() && !ina260Sensor.isInitialized())
+ result = ina260Sensor.runOnce();
+ if (ina3221Sensor.hasSensor() && !ina3221Sensor.isInitialized())
+ result = ina3221Sensor.runOnce();
+ }
+ return result;
+#else
+ return disable();
+#endif
+ } else {
+ // if we somehow got to a second run of this module with measurement disabled, then just wait forever
+ if (!moduleConfig.telemetry.power_measurement_enabled)
+ return disable();
+
+ uint32_t now = millis();
+ if (((lastSentToMesh == 0) ||
+ ((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval))) &&
+ airTime->isTxAllowedAirUtil()) {
+ sendTelemetry();
+ lastSentToMesh = now;
+ } else if (((lastSentToPhone == 0) || ((now - lastSentToPhone) >= sendToPhoneIntervalMs)) &&
+ (service.isToPhoneQueueEmpty())) {
+ // Just send to phone when it's not our time to send to mesh yet
+ // Only send while queue is empty (phone assumed connected)
+ sendTelemetry(NODENUM_BROADCAST, true);
+ lastSentToPhone = now;
+ }
+ }
+ return min(sendToPhoneIntervalMs, result);
+}
+bool PowerTelemetryModule::wantUIFrame()
+{
+ return moduleConfig.telemetry.power_screen_enabled;
+}
+
+uint32_t GetTimeyWimeySinceMeshPacket(const meshtastic_MeshPacket *mp)
+{
+ uint32_t now = getTime();
+
+ uint32_t last_seen = mp->rx_time;
+ int delta = (int)(now - last_seen);
+ if (delta < 0) // our clock must be slightly off still - not set from GPS yet
+ delta = 0;
+
+ return delta;
+}
+
+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");
+ if (lastMeasurementPacket == nullptr) {
+ display->setFont(FONT_SMALL);
+ display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement");
+ return;
+ }
+
+ meshtastic_Telemetry lastMeasurement;
+
+ uint32_t agoSecs = GetTimeyWimeySinceMeshPacket(lastMeasurementPacket);
+ const char *lastSender = getSenderShortName(*lastMeasurementPacket);
+
+ auto &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");
+ LOG_ERROR("Unable to decode last packet");
+ return;
+ }
+
+ display->setFont(FONT_SMALL);
+ String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C";
+ display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
+ if (lastMeasurement.variant.power_metrics.ch1_voltage != 0) {
+ display->drawString(x, y += fontHeight(FONT_SMALL),
+ "Ch 1 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch1_voltage, 0) + "V / " +
+ String(lastMeasurement.variant.power_metrics.ch1_current, 0) + "mA");
+ display->drawString(x, y += fontHeight(FONT_SMALL),
+ "Ch 2 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch2_voltage, 0) + "V / " +
+ String(lastMeasurement.variant.power_metrics.ch2_current, 0) + "mA");
+ display->drawString(x, y += fontHeight(FONT_SMALL),
+ "Ch 3 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch3_voltage, 0) + "V / " +
+ String(lastMeasurement.variant.power_metrics.ch3_current, 0) + "mA");
+ }
+}
+
+bool PowerTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
+{
+ if (t->which_variant == meshtastic_Telemetry_power_metrics_tag) {
+#ifdef DEBUG_PORT
+ const char *sender = getSenderShortName(mp);
+
+ LOG_INFO("(Received from %s): ch1_voltage=%f, ch1_current=%f, ch2_voltage=%f, ch2_current=%f, "
+ "ch3_voltage=%f, ch3_current=%f\n",
+ sender, t->variant.power_metrics.ch1_voltage, t->variant.power_metrics.ch1_current,
+ t->variant.power_metrics.ch2_voltage, t->variant.power_metrics.ch2_current, t->variant.power_metrics.ch3_voltage,
+ t->variant.power_metrics.ch3_current);
+#endif
+ // release previous packet before occupying a new spot
+ if (lastMeasurementPacket != nullptr)
+ packetPool.release(lastMeasurementPacket);
+
+ lastMeasurementPacket = packetPool.allocCopy(mp);
+ }
+
+ return false; // Let others look at this message also if they want
+}
+
+bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
+{
+ meshtastic_Telemetry m;
+ bool valid = false;
+ m.time = getTime();
+ m.which_variant = meshtastic_Telemetry_power_metrics_tag;
+
+ m.variant.power_metrics.ch1_voltage = 0;
+ m.variant.power_metrics.ch1_current = 0;
+ m.variant.power_metrics.ch2_voltage = 0;
+ m.variant.power_metrics.ch2_current = 0;
+ m.variant.power_metrics.ch3_voltage = 0;
+ m.variant.power_metrics.ch3_current = 0;
+#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
+ if (ina219Sensor.hasSensor())
+ valid = ina219Sensor.getMetrics(&m);
+ if (ina260Sensor.hasSensor())
+ valid = ina260Sensor.getMetrics(&m);
+ if (ina3221Sensor.hasSensor())
+ valid = ina3221Sensor.getMetrics(&m);
+#endif
+
+ if (valid) {
+ LOG_INFO("(Sending): ch1_voltage=%f, ch1_current=%f, ch2_voltage=%f, ch2_current=%f, "
+ "ch3_voltage=%f, ch3_current=%f\n",
+ m.variant.power_metrics.ch1_voltage, m.variant.power_metrics.ch1_current, m.variant.power_metrics.ch2_voltage,
+ m.variant.power_metrics.ch2_current, m.variant.power_metrics.ch3_voltage, m.variant.power_metrics.ch3_current);
+
+ sensor_read_error_count = 0;
+
+ meshtastic_MeshPacket *p = allocDataProtobuf(m);
+ p->to = dest;
+ p->decoded.want_response = false;
+ if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR)
+ p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
+ else
+ p->priority = meshtastic_MeshPacket_Priority_MIN;
+ // release previous packet before occupying a new spot
+ if (lastMeasurementPacket != nullptr)
+ packetPool.release(lastMeasurementPacket);
+
+ lastMeasurementPacket = packetPool.allocCopy(*p);
+ if (phoneOnly) {
+ LOG_INFO("Sending packet to phone\n");
+ service.sendToPhone(p);
+ } else {
+ LOG_INFO("Sending packet to mesh\n");
+ service.sendToMesh(p, RX_SRC_LOCAL, true);
+
+ if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR && config.power.is_power_saving) {
+ LOG_DEBUG("Starting next execution in 5 seconds and then going to sleep.\n");
+ sleepOnNextExecution = true;
+ setIntervalFromNow(5000);
+ }
+ }
+ }
+ return valid;
+}
\ No newline at end of file
diff --git a/src/modules/Telemetry/PowerTelemetry.h b/src/modules/Telemetry/PowerTelemetry.h
new file mode 100644
index 000000000..fc5b98875
--- /dev/null
+++ b/src/modules/Telemetry/PowerTelemetry.h
@@ -0,0 +1,43 @@
+#pragma once
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "NodeDB.h"
+#include "ProtobufModule.h"
+#include
+#include
+
+class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModule
+{
+ public:
+ PowerTelemetryModule()
+ : concurrency::OSThread("PowerTelemetryModule"),
+ ProtobufModule("PowerTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
+ {
+ lastMeasurementPacket = nullptr;
+ setIntervalFromNow(10 * 1000);
+ }
+ virtual bool wantUIFrame() override;
+#if !HAS_SCREEN
+ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
+#else
+ virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
+#endif
+
+ 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 meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override;
+ virtual int32_t runOnce() override;
+ /**
+ * Send our Telemetry into the mesh
+ */
+ bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
+
+ private:
+ bool firstTime = 1;
+ meshtastic_MeshPacket *lastMeasurementPacket;
+ uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
+ uint32_t lastSentToMesh = 0;
+ uint32_t lastSentToPhone = 0;
+ uint32_t sensor_read_error_count = 0;
+};
diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp
new file mode 100644
index 000000000..634f5a5c9
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp
@@ -0,0 +1,43 @@
+#include "INA3221Sensor.h"
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include "configuration.h"
+#include
+
+INA3221Sensor::INA3221Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_INA3221, "INA3221"){};
+
+int32_t INA3221Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ if (!status) {
+ ina3221.setAddr(INA3221_ADDR42_SDA);
+ ina3221.begin();
+ status = true;
+ } else {
+ status = true;
+ }
+ return initI2CSensor();
+};
+
+void INA3221Sensor::setup() {}
+
+bool INA3221Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ measurement->variant.environment_metrics.voltage = ina3221.getVoltage(INA3221_CH1);
+ measurement->variant.environment_metrics.current = ina3221.getCurrent(INA3221_CH1);
+ measurement->variant.power_metrics.ch1_voltage = ina3221.getVoltage(INA3221_CH1);
+ measurement->variant.power_metrics.ch1_current = ina3221.getCurrent(INA3221_CH1);
+ measurement->variant.power_metrics.ch2_voltage = ina3221.getVoltage(INA3221_CH2);
+ measurement->variant.power_metrics.ch2_current = ina3221.getCurrent(INA3221_CH2);
+ measurement->variant.power_metrics.ch3_voltage = ina3221.getVoltage(INA3221_CH3);
+ measurement->variant.power_metrics.ch3_current = ina3221.getCurrent(INA3221_CH3);
+ return true;
+}
+
+uint16_t INA3221Sensor::getBusVoltageMv()
+{
+ return lround(ina3221.getVoltage(INA3221_CH1) * 1000);
+}
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.h b/src/modules/Telemetry/Sensor/INA3221Sensor.h
new file mode 100644
index 000000000..a1c0fb2a7
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/INA3221Sensor.h
@@ -0,0 +1,16 @@
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class INA3221Sensor : public TelemetrySensor
+{
+ public:
+ INA3221Sensor();
+ int32_t runOnce() override;
+ void setup() override;
+ bool getMetrics(meshtastic_Telemetry *measurement) override;
+ virtual uint16_t getBusVoltageMv();
+
+ private:
+ INA3221 ina3221 = INA3221(INA3221_ADDR42_SDA);
+};
\ No newline at end of file
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index a9e80c947..29a634922 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -565,6 +565,13 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance);
msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage);
msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current);
+ } else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
+ msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage);
+ msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current);
+ msgPayload["voltage_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_voltage);
+ msgPayload["current_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_current);
+ msgPayload["voltage_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_voltage);
+ msgPayload["current_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_current);
}
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
diff --git a/src/platform/portduino/PiHal.h b/src/platform/portduino/PiHal.h
new file mode 100644
index 000000000..f10040583
--- /dev/null
+++ b/src/platform/portduino/PiHal.h
@@ -0,0 +1,155 @@
+#ifndef PI_HAL_H
+#define PI_HAL_H
+
+// include RadioLib
+#include
+
+// include the library for Raspberry GPIO pins
+#include "pigpio.h"
+
+// create a new Raspberry Pi hardware abstraction layer
+// using the pigpio library
+// the HAL must inherit from the base RadioLibHal class
+// and implement all of its virtual methods
+class PiHal : public RadioLibHal
+{
+ public:
+ // default constructor - initializes the base HAL and any needed private members
+ PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000)
+ : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE), _spiChannel(spiChannel),
+ _spiSpeed(spiSpeed)
+ {
+ }
+
+ void init() override
+ {
+ // first initialise pigpio library
+ gpioInitialise();
+
+ // now the SPI
+ spiBegin();
+
+ // Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio
+ // gpioSetMode(18, PI_OUTPUT);
+ // gpioWrite(18, PI_HIGH);
+ }
+
+ void term() override
+ {
+ // stop the SPI
+ spiEnd();
+
+ // pull the enable pin low
+ // gpioSetMode(18, PI_OUTPUT);
+ // gpioWrite(18, PI_LOW);
+
+ // finally, stop the pigpio library
+ gpioTerminate();
+ }
+
+ // GPIO-related methods (pinMode, digitalWrite etc.) should check
+ // RADIOLIB_NC as an alias for non-connected pins
+ void pinMode(uint32_t pin, uint32_t mode) override
+ {
+ if (pin == RADIOLIB_NC) {
+ return;
+ }
+
+ gpioSetMode(pin, mode);
+ }
+
+ void digitalWrite(uint32_t pin, uint32_t value) override
+ {
+ if (pin == RADIOLIB_NC) {
+ return;
+ }
+
+ gpioWrite(pin, value);
+ }
+
+ uint32_t digitalRead(uint32_t pin) override
+ {
+ if (pin == RADIOLIB_NC) {
+ return (0);
+ }
+
+ return (gpioRead(pin));
+ }
+
+ void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override
+ {
+ if (interruptNum == RADIOLIB_NC) {
+ return;
+ }
+ if (gpioRead(interruptNum) == 1) {
+ interruptCb();
+ } else {
+ gpioSetAlertFunc(interruptNum, (gpioISRFunc_t)interruptCb);
+ }
+ }
+
+ void detachInterrupt(uint32_t interruptNum) override
+ {
+ if (interruptNum == RADIOLIB_NC) {
+ return;
+ }
+
+ gpioSetAlertFunc(interruptNum, NULL);
+ }
+
+ void delay(unsigned long ms) override { gpioDelay(ms * 1000); }
+
+ void delayMicroseconds(unsigned long us) override { gpioDelay(us); }
+
+ unsigned long millis() override { return (gpioTick() / 1000); }
+
+ unsigned long micros() override { return (gpioTick()); }
+
+ long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override
+ {
+ if (pin == RADIOLIB_NC) {
+ return (0);
+ }
+
+ this->pinMode(pin, PI_INPUT);
+ uint32_t start = this->micros();
+ uint32_t curtick = this->micros();
+
+ while (this->digitalRead(pin) == state) {
+ if ((this->micros() - curtick) > timeout) {
+ return (0);
+ }
+ }
+
+ return (this->micros() - start);
+ }
+
+ void spiBegin()
+ {
+ if (_spiHandle < 0) {
+ _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0);
+ }
+ }
+
+ void spiBeginTransaction() {}
+
+ void spiTransfer(uint8_t *out, size_t len, uint8_t *in) { spiXfer(_spiHandle, (char *)out, (char *)in, len); }
+
+ void spiEndTransaction() {}
+
+ void spiEnd()
+ {
+ if (_spiHandle >= 0) {
+ spiClose(_spiHandle);
+ _spiHandle = -1;
+ }
+ }
+
+ private:
+ // the HAL can contain any additional private members
+ const unsigned int _spiSpeed;
+ const uint8_t _spiChannel;
+ int _spiHandle = -1;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp
index 4e957cb1e..fb71a429b 100644
--- a/src/platform/portduino/PortduinoGlue.cpp
+++ b/src/platform/portduino/PortduinoGlue.cpp
@@ -7,10 +7,15 @@
#include
#include
+
+#ifdef ARCH_RASPBERRY_PI
+#include "pigpio.h"
+
+#else
#include
+#endif
// FIXME - move setBluetoothEnable into a HALPlatform class
-
void setBluetoothEnable(bool on)
{
// not needed
@@ -88,7 +93,11 @@ void portduinoSetup()
{
printf("Setting up Meshtastic on Portduino...\n");
-#ifdef PORTDUINO_LINUX_HARDWARE
+#ifdef ARCH_RASPBERRY_PI
+ return;
+#endif
+
+#ifdef defined(PORTDUINO_LINUX_HARDWARE)
SPI.begin(); // We need to create SPI
bool usePineLora = !spiChip->isSimulated();
if (usePineLora) {
@@ -129,7 +138,6 @@ void portduinoSetup()
gpioBind(new SimGPIOPin(SX126X_RESET, "fakeLoraReset"));
gpioBind(new SimGPIOPin(LORA_DIO1, "fakeLoraIrq"));
}
-
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
// gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent());
-}
+}
\ No newline at end of file
diff --git a/src/shutdown.h b/src/shutdown.h
index 90fb19d0c..f36a7f8dd 100644
--- a/src/shutdown.h
+++ b/src/shutdown.h
@@ -14,6 +14,8 @@ void powerCommandsCheck()
NVIC_SystemReset();
#elif defined(ARCH_RP2040)
rp2040.reboot();
+#elif defined(ARCH_RASPBERRY_PI)
+ exit(EXIT_SUCCESS);
#else
rebootAtMsec = -1;
LOG_WARN("FIXME implement reboot for this platform. Note that some settings require a restart to be applied.\n");
diff --git a/variants/portduino/platformio.ini b/variants/portduino/platformio.ini
index 5bbde2adf..323609d0e 100644
--- a/variants/portduino/platformio.ini
+++ b/variants/portduino/platformio.ini
@@ -13,10 +13,10 @@ board = linux_hardware
lib_deps = ${portduino_base.lib_deps}
build_src_filter = ${portduino_base.build_src_filter}
-; The Portduino based sim environment on top of a linux OS and touching linux hardware devices
-[env:linux-arm]
+; The Raspberry Pi actually has accessible SPI and GPIO, so we can support real hardware there.
+[env:raspbian]
extends = portduino_base
-build_flags = ${portduino_base.build_flags} -O0 -lgpiod -I variants/portduino
+build_flags = ${portduino_base.build_flags} -O0 -lgpiod -I variants/portduino -DARCH_RASPBERRY_PI -DRADIOLIB_DEBUG -lpigpio
board = linux_arm
lib_deps = ${portduino_base.lib_deps}
-build_src_filter = ${portduino_base.build_src_filter}
+build_src_filter = ${portduino_base.build_src_filter}
\ No newline at end of file
diff --git a/variants/portduino/variant.h b/variants/portduino/variant.h
index 81dfd3885..2ce871ddc 100644
--- a/variants/portduino/variant.h
+++ b/variants/portduino/variant.h
@@ -1,3 +1,36 @@
+#if defined(ARCH_RASPBERRY_PI)
+#define HAS_RADIO 1
+#define GPIOD_CHIP_LABEL "pinctrl-bcm2711"
+
+// define USE_RF95
+#define USE_SX1262
+#define SX126X_TXEN 6
+#define SX126X_DIO2_AS_RF_SWITCH
+#define NO_SCREEN
+
+#define RF95_SCK 11
+#define RF95_MISO 9
+#define RF95_MOSI 10
+#define RF95_NSS RADIOLIB_NC
+
+// #define LORA_DIO0 4 // a No connect on the SX1262 module
+// #define LORA_DIO0_LABEL "GPIO_GCLK"
+#define LORA_RESET 18
+#define LORA_RESET_LABEL "GPIO18"
+#define LORA_DIO1 16 // SX1262 IRQ, called DIO0 on pinelora schematic, pin 7 on ch341f "ack" - FIXME, enable hwints in linux
+// #define LORA_DIO2 20 // SX1262 BUSY, actually connected to "DIO5" on pinelora schematic, pin 8 on ch341f "slct"
+// #define LORA_DIO3 6 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
+
+#ifdef USE_SX1262
+#define SX126X_CS 21
+#define SX126X_DIO1 16
+#define SX126X_BUSY 20
+#define SX126X_RESET LORA_RESET
+// HOPE RFM90 does not have a TCXO therefore not SX126X_E22
+#endif
+
+#else // Pine64 mode.
+
// Pine64 uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
// not found then probe for SX1262. Currently the RF95 code is disabled because I think the RF95 module won't need to ship.
// #define USE_RF95
@@ -13,7 +46,7 @@
#define LORA_RESET 14
#define LORA_DIO1 33 // SX1262 IRQ, called DIO0 on pinelora schematic, pin 7 on ch341f "ack" - FIXME, enable hwints in linux
#define LORA_DIO2 32 // SX1262 BUSY, actually connected to "DIO5" on pinelora schematic, pin 8 on ch341f "slct"
-#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
+#define LORA_DIO3 RADIOLIB_NC // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
#ifdef USE_SX1262
#define SX126X_CS 20 // CS0 on pinelora schematic, hooked to gpio D0 on ch341f
@@ -21,5 +54,6 @@
#define SX126X_BUSY LORA_DIO2
#define SX126X_RESET LORA_RESET
#define SX126X_DIO2_AS_RF_SWITCH
-// HOPE RFM90 does not have a TCXO therefore not SX126X_E22
#endif
+
+#endif
\ No newline at end of file
diff --git a/variants/rak10701/platformio.ini b/variants/rak10701/platformio.ini
new file mode 100644
index 000000000..736329eb8
--- /dev/null
+++ b/variants/rak10701/platformio.ini
@@ -0,0 +1,18 @@
+; The very slick RAK wireless RAK10701 Field Tester device. Note you will have to flash to Arduino bootloader to use this firmware. Be aware touch is not currently working.
+[env:rak10701]
+extends = nrf52840_base
+board = wiscore_rak4631
+build_flags = ${nrf52840_base.build_flags} -Ivariants/rak10701 -D RAK_4631
+ -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
+build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak10701> + + +
+lib_deps =
+ ${nrf52840_base.lib_deps}
+ ${networking_base.lib_deps}
+ melopero/Melopero RV3028@^1.1.0
+ https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2
+ rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
+ bodmer/TFT_eSPI
+debug_tool = jlink
+; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
+;upload_protocol = jlink
\ No newline at end of file
diff --git a/variants/rak10701/variant.cpp b/variants/rak10701/variant.cpp
new file mode 100644
index 000000000..2b4bd39a6
--- /dev/null
+++ b/variants/rak10701/variant.cpp
@@ -0,0 +1,41 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "variant.h"
+#include "nrf.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+
+const uint32_t g_ADigitalPinMap[] = {
+ // P0
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+
+ // P1
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
+
+void initVariant()
+{
+ // LED1 & LED2
+ pinMode(PIN_LED1, OUTPUT);
+ ledOff(PIN_LED1);
+
+ pinMode(PIN_LED2, OUTPUT);
+ ledOff(PIN_LED2);
+}
\ No newline at end of file
diff --git a/variants/rak10701/variant.h b/variants/rak10701/variant.h
new file mode 100644
index 000000000..3b771d62b
--- /dev/null
+++ b/variants/rak10701/variant.h
@@ -0,0 +1,329 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef _VARIANT_RAK4630_
+#define _VARIANT_RAK4630_
+
+#define RAK4630
+
+/** Master clock frequency */
+#define VARIANT_MCK (64000000ul)
+
+#define USE_LFXO // Board uses 32khz crystal for LF
+// define USE_LFRC // Board uses RC for LF
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+
+#include "WVariant.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Number of pins defined in PinDescription array
+#define PINS_COUNT (48)
+#define NUM_DIGITAL_PINS (48)
+#define NUM_ANALOG_INPUTS (6)
+#define NUM_ANALOG_OUTPUTS (0)
+
+// LEDs
+#define PIN_LED1 (35)
+#define PIN_LED2 (36)
+
+#define LED_BUILTIN PIN_LED1
+#define LED_CONN PIN_LED2
+
+#define LED_GREEN PIN_LED1
+#define LED_BLUE PIN_LED2
+
+#define LED_STATE_ON 1 // State when LED is litted
+
+/*
+ * Buttons
+ */
+
+#define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion such as the RAK14014 or RAK14015 TFT modules
+#define BUTTON_NEED_PULLUP
+#define PIN_BUTTON2 12
+#define PIN_BUTTON3 24
+#define PIN_BUTTON4 25
+
+/*
+ * Analog pins
+ */
+#define PIN_A0 (5)
+#define PIN_A1 (31)
+#define PIN_A2 (28)
+#define PIN_A3 (29)
+#define PIN_A4 (30)
+#define PIN_A5 (31)
+#define PIN_A6 (0xff)
+#define PIN_A7 (0xff)
+
+static const uint8_t A0 = PIN_A0;
+static const uint8_t A1 = PIN_A1;
+static const uint8_t A2 = PIN_A2;
+static const uint8_t A3 = PIN_A3;
+static const uint8_t A4 = PIN_A4;
+static const uint8_t A5 = PIN_A5;
+static const uint8_t A6 = PIN_A6;
+static const uint8_t A7 = PIN_A7;
+#define ADC_RESOLUTION 14
+
+// Other pins
+#define PIN_AREF (2)
+#define PIN_NFC1 (9)
+#define PIN_NFC2 (10)
+
+static const uint8_t AREF = PIN_AREF;
+
+/*
+ * Serial interfaces
+ */
+#define PIN_SERIAL1_RX (15)
+#define PIN_SERIAL1_TX (16)
+
+// Connected to Jlink CDC
+#define PIN_SERIAL2_RX (8)
+#define PIN_SERIAL2_TX (6)
+
+/*
+ * SPI Interfaces
+ */
+#define SPI_INTERFACES_COUNT 2
+
+#define PIN_SPI_MISO (45)
+#define PIN_SPI_MOSI (44)
+#define PIN_SPI_SCK (43)
+
+#define PIN_SPI1_MISO (29) // (0 + 29)
+#define PIN_SPI1_MOSI (30) // (0 + 30)
+#define PIN_SPI1_SCK (3) // (0 + 3)
+
+static const uint8_t SS = 42;
+static const uint8_t MOSI = PIN_SPI_MOSI;
+static const uint8_t MISO = PIN_SPI_MISO;
+static const uint8_t SCK = PIN_SPI_SCK;
+
+/*
+ * eink display pins
+ */
+
+#define PIN_EINK_CS (0 + 26)
+#define PIN_EINK_BUSY (0 + 4)
+#define PIN_EINK_DC (0 + 17)
+#define PIN_EINK_RES (-1)
+#define PIN_EINK_SCLK (0 + 3)
+#define PIN_EINK_MOSI (0 + 30) // also called SDI
+
+// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
+// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
+// #define PIN_EINK_PWR_ON (-1)
+
+// #define USE_EINK
+
+// RAKRGB
+#define HAS_NCP5623
+
+/*
+ * Wire Interfaces
+ */
+#define WIRE_INTERFACES_COUNT 1
+
+#define PIN_WIRE_SDA (13)
+#define PIN_WIRE_SCL (14)
+
+// QSPI Pins
+#define PIN_QSPI_SCK 3
+#define PIN_QSPI_CS 26
+#define PIN_QSPI_IO0 30
+#define PIN_QSPI_IO1 29
+#define PIN_QSPI_IO2 28
+#define PIN_QSPI_IO3 2
+
+// On-board QSPI Flash
+#define EXTERNAL_FLASH_DEVICES IS25LP080D
+#define EXTERNAL_FLASH_USE_QSPI
+
+/* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports
+ RAK5005-O <-> nRF52840
+ IO1 <-> P0.17 (Arduino GPIO number 17)
+ IO2 <-> P1.02 (Arduino GPIO number 34)
+ IO3 <-> P0.21 (Arduino GPIO number 21)
+ IO4 <-> P0.04 (Arduino GPIO number 4)
+ IO5 <-> P0.09 (Arduino GPIO number 9)
+ IO6 <-> P0.10 (Arduino GPIO number 10)
+ IO7 <-> P0.28 (Arduino GPIO number 28)
+ SW1 <-> P0.01 (Arduino GPIO number 1)
+ A0 <-> P0.04/AIN2 (Arduino Analog A2
+ A1 <-> P0.31/AIN7 (Arduino Analog A7
+ SPI_CS <-> P0.26 (Arduino GPIO number 26)
+ */
+
+// No reason not to have the RAK Wireless pin defs here too. This allows code from example RAK sketches to run without
+// modification.
+
+static const uint8_t WB_IO1 = 17; // SLOT_A SLOT_B
+static const uint8_t WB_IO2 = 34; // SLOT_A SLOT_B
+static const uint8_t WB_IO3 = 21; // SLOT_C
+static const uint8_t WB_IO4 = 4; // SLOT_C
+static const uint8_t WB_IO5 = 9; // SLOT_D
+static const uint8_t WB_IO6 = 10; // SLOT_D
+static const uint8_t WB_SW1 = 33; // IO_SLOT
+static const uint8_t WB_A0 = 5; // IO_SLOT
+static const uint8_t WB_A1 = 31; // IO_SLOT
+static const uint8_t WB_I2C1_SDA = 13; // SENSOR_SLOT IO_SLOT
+static const uint8_t WB_I2C1_SCL = 14; // SENSOR_SLOT IO_SLOT
+static const uint8_t WB_I2C2_SDA = 24; // IO_SLOT
+static const uint8_t WB_I2C2_SCL = 25; // IO_SLOT
+static const uint8_t WB_SPI_CS = 26; // IO_SLOT
+static const uint8_t WB_SPI_CLK = 3; // IO_SLOT
+static const uint8_t WB_SPI_MISO = 29; // IO_SLOT
+static const uint8_t WB_SPI_MOSI = 30; // IO_SLOT
+
+// RAK4630 LoRa module
+
+/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ )
+
+P1.10 NSS SPI NSS (Arduino GPIO number 42)
+P1.11 SCK SPI CLK (Arduino GPIO number 43)
+P1.12 MOSI SPI MOSI (Arduino GPIO number 44)
+P1.13 MISO SPI MISO (Arduino GPIO number 45)
+P1.14 BUSY BUSY signal (Arduino GPIO number 46)
+P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47)
+P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38)
+
+Important for successful SX1262 initialization:
+
+* Setup DIO2 to control the antenna switch
+* Setup DIO3 to control the TCXO power supply
+* Setup the SX1262 to use it's DCDC regulator and not the LDO
+* RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the
+control of the antenna switch
+
+SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
+
+*/
+
+#define USE_SX1262
+#define SX126X_CS (42)
+#define SX126X_DIO1 (47)
+#define SX126X_BUSY (46)
+#define SX126X_RESET (38)
+// #define SX126X_TXEN (39)
+// #define SX126X_RXEN (37)
+#define SX126X_POWER_EN (37)
+// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
+#define SX126X_DIO2_AS_RF_SWITCH
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+
+// enables 3.3V periphery like GPS or IO Module
+#define PIN_3V3_EN (34)
+
+// RAK1910 GPS module
+// If using the wisblock GPS module and pluged into Port A on WisBlock base
+// IO1 is hooked to PPS (pin 12 on header) = gpio 17
+// IO2 is hooked to GPS RESET = gpio 34, but it can not be used to this because IO2 is ALSO used to control 3V3_S power (1 is on).
+// Therefore must be 1 to keep peripherals powered
+// Power is on the controllable 3V3_S rail
+// #define PIN_GPS_RESET (34)
+#define PIN_GPS_EN PIN_3V3_EN
+#define PIN_GPS_PPS (17) // Pulse per second input from the GPS
+
+#define GPS_RX_PIN PIN_SERIAL1_RX
+#define GPS_TX_PIN PIN_SERIAL1_TX
+
+// Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press
+
+// RAK12002 RTC Module
+#define RV3028_RTC (uint8_t)0b1010010
+
+// RAK18001 Buzzer in Slot C
+// #define PIN_BUZZER 21 // IO3 is PWM2
+// NEW: set this via protobuf instead!
+
+// Battery
+// The battery sense is hooked to pin A0 (5)
+#define BATTERY_PIN PIN_A0
+// and has 12 bit resolution
+#define BATTERY_SENSE_RESOLUTION_BITS 12
+#define BATTERY_SENSE_RESOLUTION 4096.0
+// Definition of milliVolt per LSB => 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
+#define VBAT_MV_PER_LSB (0.73242188F)
+// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M))
+#define VBAT_DIVIDER (0.4F)
+// Compensation factor for the VBAT divider
+#define VBAT_DIVIDER_COMP (1.73)
+// Fixed calculation of milliVolt from compensation value
+#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
+#undef AREF_VOLTAGE
+#define AREF_VOLTAGE 3.0
+#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
+#define ADC_MULTIPLIER VBAT_DIVIDER_COMP // REAL_VBAT_MV_PER_LSB
+#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)
+
+#define HAS_RTC 1
+
+#define HAS_ETHERNET 1
+
+#define RAK_4631 1
+
+#define PIN_ETHERNET_RESET 21
+#define PIN_ETHERNET_SS PIN_EINK_CS
+#define ETH_SPI_PORT SPI1
+#define AQ_SET_PIN 10
+
+#ifdef __cplusplus
+}
+#endif
+
+#define RAK14014 // Tell it we have a RAK14014
+#define USER_SETUP_LOADED 1
+#define DISABLE_ALL_LIBRARY_WARNINGS 1
+#define ST7789_DRIVER 1
+#define TFT_WIDTH 240
+#define TFT_HEIGHT 320
+#define TFT_MISO WB_SPI_MISO
+#define TFT_MOSI WB_SPI_MOSI
+#define TFT_SCLK WB_SPI_CLK
+#define TFT_CS WB_SPI_CS
+#define TFT_DC WB_IO4
+#define TFT_RST -1
+#define TFT_BL WB_IO3
+#define LOAD_GLCD 1
+#define LOAD_GFXFF 1
+#define TFT_RGB_ORDER 0
+#define SPI_FREQUENCY 50000000
+#define TFT_SPI_PORT SPI1
+#define ST7789_CS WB_SPI_CS // Adds compatibility with the rest of the checking for a ST7789 TFT.
+
+#define SCREEN_ROTATE
+#define SCREEN_TRANSITION_FRAMERATE 5
+
+#define HAS_TOUCHSCREEN 0
+#define SCREEN_TOUCH_INT 10 // From tp.h on the tracker open source code.
+#define TOUCH_I2C_PORT 0
+#define TOUCH_SLAVE_ADDRESS 0x5D // GT911
+
+/*----------------------------------------------------------------------------
+ * Arduino objects - C++ only
+ *----------------------------------------------------------------------------*/
+
+#endif
diff --git a/variants/rak11310/variant.h b/variants/rak11310/variant.h
index c2ab3628d..1ea6d141d 100644
--- a/variants/rak11310/variant.h
+++ b/variants/rak11310/variant.h
@@ -22,6 +22,8 @@
// ratio of voltage divider = 3.0 (R17=200k, R18=100k)
#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic
+#define DETECTION_SENSOR_EN 28
+
#define USE_SX1262
#undef RF95_SCK
@@ -51,4 +53,4 @@
// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
-#endif
+#endif
\ No newline at end of file
diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h
index 7b5f6b14d..89bb62c73 100644
--- a/variants/rak4631/variant.h
+++ b/variants/rak4631/variant.h
@@ -201,6 +201,8 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
*/
+#define DETECTION_SENSOR_EN 4
+
#define USE_SX1262
#define SX126X_CS (42)
#define SX126X_DIO1 (47)
@@ -223,7 +225,7 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
// Therefore must be 1 to keep peripherals powered
// Power is on the controllable 3V3_S rail
// #define PIN_GPS_RESET (34)
-#define PIN_GPS_EN PIN_3V3_EN
+// #define PIN_GPS_EN PIN_3V3_EN
#define PIN_GPS_PPS (17) // Pulse per second input from the GPS
#define GPS_RX_PIN PIN_SERIAL1_RX
@@ -277,4 +279,4 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
-#endif
+#endif
\ No newline at end of file
diff --git a/version.properties b/version.properties
index 006a90013..972a6f6de 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 2
-build = 13
+build = 14