diff --git a/platformio.ini b/platformio.ini
index 1d8083f70..a833c42a5 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -2,7 +2,7 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
-;default_envs = tbeam
+default_envs = tbeam
;default_envs = pico
;default_envs = tbeam-s3-core
;default_envs = tbeam0.7
@@ -109,3 +109,4 @@ lib_deps =
adafruit/Adafruit SHTC3 Library@^1.0.0
adafruit/Adafruit LPS2X@^2.0.4
adafruit/Adafruit SHT31 Library@^2.2.0
+ adafruit/Adafruit PM25 AQI Sensor@^1.0.6
diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h
index 4352eba13..586ffaa3c 100644
--- a/src/BluetoothCommon.h
+++ b/src/BluetoothCommon.h
@@ -17,4 +17,14 @@
extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[];
/// Given a level between 0-100, update the BLE attribute
-void updateBatteryLevel(uint8_t level);
\ No newline at end of file
+void updateBatteryLevel(uint8_t level);
+
+class BluetoothApi
+{
+ public:
+ virtual void setup();
+ virtual void shutdown();
+ virtual void clearBonds();
+ virtual bool isConnected();
+ virtual int getRssi() = 0;
+};
\ No newline at end of file
diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp
index c36c65efc..e96b36c11 100644
--- a/src/PowerFSM.cpp
+++ b/src/PowerFSM.cpp
@@ -78,8 +78,8 @@ static void lsIdle()
case ESP_SLEEP_WAKEUP_TIMER:
// Normal case: timer expired, we should just go back to sleep ASAP
- setLed(true); // briefly turn on led
- wakeCause2 = doLightSleep(1); // leave led on for 1ms
+ setLed(true); // briefly turn on led
+ wakeCause2 = doLightSleep(100); // leave led on for 1ms
secsSlept += sleepTime;
// LOG_INFO("sleeping, flash led!\n");
diff --git a/src/configuration.h b/src/configuration.h
index 6181034a5..f35fff4e0 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -116,6 +116,7 @@ along with this program. If not, see .
#define LPS22HB_ADDR 0x5C
#define LPS22HB_ADDR_ALT 0x5D
#define SHT31_ADDR 0x44
+#define PMSA0031_ADDR 0x12
// -----------------------------------------------------------------------------
// Security
diff --git a/src/detect/i2cScan.h b/src/detect/i2cScan.h
index 87ca55957..a2d7b7baf 100644
--- a/src/detect/i2cScan.h
+++ b/src/detect/i2cScan.h
@@ -218,6 +218,10 @@ void scanI2Cdevice()
LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC5883L] = addr;
}
+ if (addr == PMSA0031_ADDR) {
+ LOG_INFO("PMSA0031 air quality sensor found\n");
+ nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] = addr;
+ }
} else if (err == 4) {
LOG_ERROR("Unknow error at address 0x%x\n", addr);
}
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index ed5e1c3a0..09cafc348 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -380,13 +380,16 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
display->setColor(BLACK);
}
- tm *tm = localtime(reinterpret_cast(&mp.rx_time));
+ uint32_t seconds = sinceReceived(&mp);
+ uint32_t minutes = seconds / 60;
+ uint32_t hours = minutes / 60;
+ uint32_t days = hours / 24;
if (config.display.heading_bold) {
- display->drawStringf(1 + x, 0 + y, tempBuf, "[%02d:%02d:%02d] From: %s", tm->tm_hour, tm->tm_min, tm->tm_sec,
+ display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds),
(node && node->has_user) ? node->user.short_name : "???");
}
- display->drawStringf(0 + x, 0 + y, tempBuf, "[%02d:%02d:%02d] From: %s", tm->tm_hour, tm->tm_min, tm->tm_sec,
+ display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds),
(node && node->has_user) ? node->user.short_name : "???");
display->setColor(WHITE);
@@ -417,38 +420,6 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
}
}
-#if 0
- /// Draw a series of fields in a row, wrapping to multiple rows if needed
- /// @return the max y we ended up printing to
- static uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
- {
- // The coordinates define the left starting point of the text
- display->setTextAlignment(TEXT_ALIGN_LEFT);
-
- const char **f = fields;
- int xo = x, yo = y;
- const int COLUMNS = 2; // hardwired for two columns per row....
- int col = 0; // track which column we are on
- while (*f) {
- display->drawString(xo, yo, *f);
- xo += SCREEN_WIDTH / COLUMNS;
- // Wrap to next row, if needed.
- if (++col >= COLUMNS) {
- xo = x;
- yo += FONT_HEIGHT_SMALL;
- col = 0;
- }
- f++;
- }
- if (col != 0) {
- // Include last incomplete line in our total.
- yo += FONT_HEIGHT_SMALL;
- }
-
- return yo;
- }
-#endif
-
// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus)
{
@@ -1365,6 +1336,20 @@ void Screen::blink()
dispdev.setBrightness(brightness);
}
+String Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
+{
+ String uptime;
+ if (days >= 2)
+ uptime = String(days) + "d";
+ else if (hours >= 2)
+ uptime = String(hours) + "h";
+ else if (minutes >= 1)
+ uptime = String(minutes) + "m";
+ else
+ uptime = String(seconds) + "s";
+ return uptime;
+}
+
void Screen::handlePrint(const char *text)
{
// the string passed into us probably has a newline, but that would confuse the logging system
@@ -1729,15 +1714,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
display->setColor(WHITE);
// Show uptime as days, hours, minutes OR seconds
- String uptime;
- if (days >= 2)
- uptime += String(days) + "d ";
- else if (hours >= 2)
- uptime += String(hours) + "h ";
- else if (minutes >= 1)
- uptime += String(minutes) + "m ";
- else
- uptime += String(seconds) + "s ";
+ String uptime = screen->drawTimeDelta(days, hours, minutes, seconds);
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice);
if (rtc_sec > 0) {
@@ -1753,7 +1730,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
char timebuf[9];
- snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", hour, min, sec);
+ snprintf(timebuf, sizeof(timebuf), " %02d:%02d:%02d", hour, min, sec);
uptime += timebuf;
}
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index db851e8bb..1d732ad4c 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -206,6 +206,9 @@ class Screen : public concurrency::OSThread
}
}
+ /// generates a very brief time delta display
+ String drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds);
+
/// Overrides the default utf8 character conversion, to replace empty space with question marks
static char customFontTableLookup(const uint8_t ch)
{
diff --git a/src/main.cpp b/src/main.cpp
index 4f65ff51b..89148c22b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -33,6 +33,12 @@
#ifdef ARCH_ESP32
#include "mesh/http/WebServer.h"
#include "nimble/NimbleBluetooth.h"
+NimbleBluetooth *nimbleBluetooth;
+#endif
+
+#ifdef ARCH_NRF52
+#include "NRF52Bluetooth.h"
+NRF52Bluetooth *nrf52Bluetooth;
#endif
#if HAS_WIFI
@@ -270,7 +276,6 @@ void setup()
LOG_INFO("PCF8563 RTC found\n");
}
#endif
-
// We need to scan here to decide if we have a screen for nodeDB.init()
scanI2Cdevice();
diff --git a/src/main.h b/src/main.h
index 9d965b0fc..b1bee1b06 100644
--- a/src/main.h
+++ b/src/main.h
@@ -9,6 +9,14 @@
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include
#endif
+#if defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2)
+#include "nimble/NimbleBluetooth.h"
+extern NimbleBluetooth *nimbleBluetooth;
+#endif
+#ifdef ARCH_NRF52
+#include "NRF52Bluetooth.h"
+extern NRF52Bluetooth *nrf52Bluetooth;
+#endif
extern uint8_t screen_found;
extern uint8_t screen_model;
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 37697bc18..89063f550 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -599,6 +599,17 @@ uint32_t sinceLastSeen(const meshtastic_NodeInfo *n)
return delta;
}
+uint32_t sinceReceived(const meshtastic_MeshPacket *p)
+{
+ uint32_t now = getTime();
+
+ int delta = (int)(now - p->rx_time);
+ if (delta < 0) // our clock must be slightly off still - not set from GPS yet
+ delta = 0;
+
+ return delta;
+}
+
#define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
size_t NodeDB::getNumOnlineNodes()
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index 106d35402..a6fbd9cb0 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -32,6 +32,9 @@ extern meshtastic_User &owner;
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
uint32_t sinceLastSeen(const meshtastic_NodeInfo *n);
+/// Given a packet, return how many seconds in the past (vs now) it was received
+uint32_t sinceReceived(const meshtastic_MeshPacket *p);
+
class NodeDB
{
// NodeNum provisionalNodeNum; // if we are trying to find a node num this is our current attempt
diff --git a/src/mesh/generated/meshtastic/admin.pb.c b/src/mesh/generated/meshtastic/admin.pb.c
index 1f668dabc..c897c1760 100644
--- a/src/mesh/generated/meshtastic/admin.pb.c
+++ b/src/mesh/generated/meshtastic/admin.pb.c
@@ -9,6 +9,9 @@
PB_BIND(meshtastic_AdminMessage, meshtastic_AdminMessage, 2)
+PB_BIND(meshtastic_HamParameters, meshtastic_HamParameters, AUTO)
+
+
diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h
index c47fb886f..25bc77241 100644
--- a/src/mesh/generated/meshtastic/admin.pb.h
+++ b/src/mesh/generated/meshtastic/admin.pb.h
@@ -9,6 +9,7 @@
#include "meshtastic/device_metadata.pb.h"
#include "meshtastic/mesh.pb.h"
#include "meshtastic/module_config.pb.h"
+#include "meshtastic/connection_status.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
@@ -56,6 +57,18 @@ typedef enum _meshtastic_AdminMessage_ModuleConfigType {
} meshtastic_AdminMessage_ModuleConfigType;
/* Struct definitions */
+/* Parameters for setting up Meshtastic for ameteur radio usage */
+typedef struct _meshtastic_HamParameters {
+ /* Amateur radio call sign, eg. KD2ABC */
+ char call_sign[8];
+ /* Transmit power in dBm at the LoRA transceiver, not including any amplification */
+ int32_t tx_power;
+ /* The selected frequency of LoRA operation
+ Please respect your local laws, regulations, and band plans.
+ Ensure your radio is capable of operating of the selected frequency before setting this. */
+ float frequency;
+} meshtastic_HamParameters;
+
/* This message is handled by the Admin module and is responsible for all settings/channel read/write operations.
This message is used to do settings operations to both remote AND local nodes.
(Prior to 1.2 these operations were done via special ToRadio operations) */
@@ -91,6 +104,12 @@ typedef struct _meshtastic_AdminMessage {
bool get_ringtone_request;
/* Get the Ringtone in the response to this message. */
char get_ringtone_response[231];
+ /* Request the node to send it's connection status */
+ bool get_device_connection_status_request;
+ /* Device connection status response */
+ meshtastic_DeviceConnectionStatus get_device_connection_status_response;
+ /* Setup a node for licensed amateur (ham) radio operation */
+ meshtastic_HamParameters set_ham_mode;
/* Set the owner for this node */
meshtastic_User set_owner;
/* Set channels (using the new API).
@@ -147,11 +166,17 @@ extern "C" {
#define meshtastic_AdminMessage_payload_variant_get_module_config_request_ENUMTYPE meshtastic_AdminMessage_ModuleConfigType
+
/* Initializer values for message structs */
#define meshtastic_AdminMessage_init_default {0, {0}}
+#define meshtastic_HamParameters_init_default {"", 0, 0}
#define meshtastic_AdminMessage_init_zero {0, {0}}
+#define meshtastic_HamParameters_init_zero {"", 0, 0}
/* Field tags (for use in manual encoding/decoding) */
+#define meshtastic_HamParameters_call_sign_tag 1
+#define meshtastic_HamParameters_tx_power_tag 2
+#define meshtastic_HamParameters_frequency_tag 3
#define meshtastic_AdminMessage_get_channel_request_tag 1
#define meshtastic_AdminMessage_get_channel_response_tag 2
#define meshtastic_AdminMessage_get_owner_request_tag 3
@@ -166,6 +191,9 @@ extern "C" {
#define meshtastic_AdminMessage_get_device_metadata_response_tag 13
#define meshtastic_AdminMessage_get_ringtone_request_tag 14
#define meshtastic_AdminMessage_get_ringtone_response_tag 15
+#define meshtastic_AdminMessage_get_device_connection_status_request_tag 16
+#define meshtastic_AdminMessage_get_device_connection_status_response_tag 17
+#define meshtastic_AdminMessage_set_ham_mode_tag 18
#define meshtastic_AdminMessage_set_owner_tag 32
#define meshtastic_AdminMessage_set_channel_tag 33
#define meshtastic_AdminMessage_set_config_tag 34
@@ -197,6 +225,9 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,get_device_metadata_request,
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_device_metadata_response,get_device_metadata_response), 13) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,get_ringtone_request,get_ringtone_request), 14) \
X(a, STATIC, ONEOF, STRING, (payload_variant,get_ringtone_response,get_ringtone_response), 15) \
+X(a, STATIC, ONEOF, BOOL, (payload_variant,get_device_connection_status_request,get_device_connection_status_request), 16) \
+X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_device_connection_status_response,get_device_connection_status_response), 17) \
+X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_ham_mode,set_ham_mode), 18) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \
@@ -218,18 +249,30 @@ X(a, STATIC, ONEOF, INT32, (payload_variant,nodedb_reset,nodedb_reset),
#define meshtastic_AdminMessage_payload_variant_get_config_response_MSGTYPE meshtastic_Config
#define meshtastic_AdminMessage_payload_variant_get_module_config_response_MSGTYPE meshtastic_ModuleConfig
#define meshtastic_AdminMessage_payload_variant_get_device_metadata_response_MSGTYPE meshtastic_DeviceMetadata
+#define meshtastic_AdminMessage_payload_variant_get_device_connection_status_response_MSGTYPE meshtastic_DeviceConnectionStatus
+#define meshtastic_AdminMessage_payload_variant_set_ham_mode_MSGTYPE meshtastic_HamParameters
#define meshtastic_AdminMessage_payload_variant_set_owner_MSGTYPE meshtastic_User
#define meshtastic_AdminMessage_payload_variant_set_channel_MSGTYPE meshtastic_Channel
#define meshtastic_AdminMessage_payload_variant_set_config_MSGTYPE meshtastic_Config
#define meshtastic_AdminMessage_payload_variant_set_module_config_MSGTYPE meshtastic_ModuleConfig
+#define meshtastic_HamParameters_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, STRING, call_sign, 1) \
+X(a, STATIC, SINGULAR, INT32, tx_power, 2) \
+X(a, STATIC, SINGULAR, FLOAT, frequency, 3)
+#define meshtastic_HamParameters_CALLBACK NULL
+#define meshtastic_HamParameters_DEFAULT NULL
+
extern const pb_msgdesc_t meshtastic_AdminMessage_msg;
+extern const pb_msgdesc_t meshtastic_HamParameters_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_AdminMessage_fields &meshtastic_AdminMessage_msg
+#define meshtastic_HamParameters_fields &meshtastic_HamParameters_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_AdminMessage_size 234
+#define meshtastic_HamParameters_size 25
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/meshtastic/connection_status.pb.c b/src/mesh/generated/meshtastic/connection_status.pb.c
new file mode 100644
index 000000000..0675bc815
--- /dev/null
+++ b/src/mesh/generated/meshtastic/connection_status.pb.c
@@ -0,0 +1,27 @@
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.4.7 */
+
+#include "meshtastic/connection_status.pb.h"
+#if PB_PROTO_HEADER_VERSION != 40
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+PB_BIND(meshtastic_DeviceConnectionStatus, meshtastic_DeviceConnectionStatus, AUTO)
+
+
+PB_BIND(meshtastic_WifiConnectionStatus, meshtastic_WifiConnectionStatus, AUTO)
+
+
+PB_BIND(meshtastic_EthernetConnectionStatus, meshtastic_EthernetConnectionStatus, AUTO)
+
+
+PB_BIND(meshtastic_NetworkConnectionStatus, meshtastic_NetworkConnectionStatus, AUTO)
+
+
+PB_BIND(meshtastic_BluetoothConnectionStatus, meshtastic_BluetoothConnectionStatus, AUTO)
+
+
+PB_BIND(meshtastic_SerialConnectionStatus, meshtastic_SerialConnectionStatus, AUTO)
+
+
+
diff --git a/src/mesh/generated/meshtastic/connection_status.pb.h b/src/mesh/generated/meshtastic/connection_status.pb.h
new file mode 100644
index 000000000..c824f8b82
--- /dev/null
+++ b/src/mesh/generated/meshtastic/connection_status.pb.h
@@ -0,0 +1,189 @@
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.4.7 */
+
+#ifndef PB_MESHTASTIC_MESHTASTIC_CONNECTION_STATUS_PB_H_INCLUDED
+#define PB_MESHTASTIC_MESHTASTIC_CONNECTION_STATUS_PB_H_INCLUDED
+#include
+
+#if PB_PROTO_HEADER_VERSION != 40
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+/* Struct definitions */
+/* Ethernet or WiFi connection status */
+typedef struct _meshtastic_NetworkConnectionStatus {
+ /* IP address of device */
+ uint32_t ip_address;
+ /* Whether the device has an active connection or not */
+ bool is_connected;
+ /* Whether the device has an active connection to an MQTT broker or not */
+ bool is_mqtt_connected;
+ /* Whether the device is actively remote syslogging or not */
+ bool is_syslog_connected;
+} meshtastic_NetworkConnectionStatus;
+
+/* WiFi connection status */
+typedef struct _meshtastic_WifiConnectionStatus {
+ /* Connection status */
+ bool has_status;
+ meshtastic_NetworkConnectionStatus status;
+ /* WiFi access point ssid */
+ char ssid[33];
+ /* Rssi of wireless connection */
+ int32_t rssi;
+} meshtastic_WifiConnectionStatus;
+
+/* Ethernet connection status */
+typedef struct _meshtastic_EthernetConnectionStatus {
+ /* Connection status */
+ bool has_status;
+ meshtastic_NetworkConnectionStatus status;
+} meshtastic_EthernetConnectionStatus;
+
+/* Bluetooth connection status */
+typedef struct _meshtastic_BluetoothConnectionStatus {
+ /* The pairing pin for bluetooth */
+ uint32_t pin;
+ /* Rssi of bluetooth connection */
+ int32_t rssi;
+ /* Whether the device has an active connection or not */
+ bool is_connected;
+} meshtastic_BluetoothConnectionStatus;
+
+/* Serial connection status */
+typedef struct _meshtastic_SerialConnectionStatus {
+ /* The serial baud rate */
+ uint32_t baud;
+ /* Whether the device has an active connection or not */
+ bool is_connected;
+} meshtastic_SerialConnectionStatus;
+
+typedef struct _meshtastic_DeviceConnectionStatus {
+ /* WiFi Status */
+ bool has_wifi;
+ meshtastic_WifiConnectionStatus wifi;
+ /* WiFi Status */
+ bool has_ethernet;
+ meshtastic_EthernetConnectionStatus ethernet;
+ /* Bluetooth Status */
+ bool has_bluetooth;
+ meshtastic_BluetoothConnectionStatus bluetooth;
+ /* Serial Status */
+ bool has_serial;
+ meshtastic_SerialConnectionStatus serial;
+} meshtastic_DeviceConnectionStatus;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Initializer values for message structs */
+#define meshtastic_DeviceConnectionStatus_init_default {false, meshtastic_WifiConnectionStatus_init_default, false, meshtastic_EthernetConnectionStatus_init_default, false, meshtastic_BluetoothConnectionStatus_init_default, false, meshtastic_SerialConnectionStatus_init_default}
+#define meshtastic_WifiConnectionStatus_init_default {false, meshtastic_NetworkConnectionStatus_init_default, "", 0}
+#define meshtastic_EthernetConnectionStatus_init_default {false, meshtastic_NetworkConnectionStatus_init_default}
+#define meshtastic_NetworkConnectionStatus_init_default {0, 0, 0, 0}
+#define meshtastic_BluetoothConnectionStatus_init_default {0, 0, 0}
+#define meshtastic_SerialConnectionStatus_init_default {0, 0}
+#define meshtastic_DeviceConnectionStatus_init_zero {false, meshtastic_WifiConnectionStatus_init_zero, false, meshtastic_EthernetConnectionStatus_init_zero, false, meshtastic_BluetoothConnectionStatus_init_zero, false, meshtastic_SerialConnectionStatus_init_zero}
+#define meshtastic_WifiConnectionStatus_init_zero {false, meshtastic_NetworkConnectionStatus_init_zero, "", 0}
+#define meshtastic_EthernetConnectionStatus_init_zero {false, meshtastic_NetworkConnectionStatus_init_zero}
+#define meshtastic_NetworkConnectionStatus_init_zero {0, 0, 0, 0}
+#define meshtastic_BluetoothConnectionStatus_init_zero {0, 0, 0}
+#define meshtastic_SerialConnectionStatus_init_zero {0, 0}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define meshtastic_NetworkConnectionStatus_ip_address_tag 1
+#define meshtastic_NetworkConnectionStatus_is_connected_tag 2
+#define meshtastic_NetworkConnectionStatus_is_mqtt_connected_tag 3
+#define meshtastic_NetworkConnectionStatus_is_syslog_connected_tag 4
+#define meshtastic_WifiConnectionStatus_status_tag 1
+#define meshtastic_WifiConnectionStatus_ssid_tag 2
+#define meshtastic_WifiConnectionStatus_rssi_tag 3
+#define meshtastic_EthernetConnectionStatus_status_tag 1
+#define meshtastic_BluetoothConnectionStatus_pin_tag 1
+#define meshtastic_BluetoothConnectionStatus_rssi_tag 2
+#define meshtastic_BluetoothConnectionStatus_is_connected_tag 3
+#define meshtastic_SerialConnectionStatus_baud_tag 1
+#define meshtastic_SerialConnectionStatus_is_connected_tag 2
+#define meshtastic_DeviceConnectionStatus_wifi_tag 1
+#define meshtastic_DeviceConnectionStatus_ethernet_tag 2
+#define meshtastic_DeviceConnectionStatus_bluetooth_tag 3
+#define meshtastic_DeviceConnectionStatus_serial_tag 4
+
+/* Struct field encoding specification for nanopb */
+#define meshtastic_DeviceConnectionStatus_FIELDLIST(X, a) \
+X(a, STATIC, OPTIONAL, MESSAGE, wifi, 1) \
+X(a, STATIC, OPTIONAL, MESSAGE, ethernet, 2) \
+X(a, STATIC, OPTIONAL, MESSAGE, bluetooth, 3) \
+X(a, STATIC, OPTIONAL, MESSAGE, serial, 4)
+#define meshtastic_DeviceConnectionStatus_CALLBACK NULL
+#define meshtastic_DeviceConnectionStatus_DEFAULT NULL
+#define meshtastic_DeviceConnectionStatus_wifi_MSGTYPE meshtastic_WifiConnectionStatus
+#define meshtastic_DeviceConnectionStatus_ethernet_MSGTYPE meshtastic_EthernetConnectionStatus
+#define meshtastic_DeviceConnectionStatus_bluetooth_MSGTYPE meshtastic_BluetoothConnectionStatus
+#define meshtastic_DeviceConnectionStatus_serial_MSGTYPE meshtastic_SerialConnectionStatus
+
+#define meshtastic_WifiConnectionStatus_FIELDLIST(X, a) \
+X(a, STATIC, OPTIONAL, MESSAGE, status, 1) \
+X(a, STATIC, SINGULAR, STRING, ssid, 2) \
+X(a, STATIC, SINGULAR, INT32, rssi, 3)
+#define meshtastic_WifiConnectionStatus_CALLBACK NULL
+#define meshtastic_WifiConnectionStatus_DEFAULT NULL
+#define meshtastic_WifiConnectionStatus_status_MSGTYPE meshtastic_NetworkConnectionStatus
+
+#define meshtastic_EthernetConnectionStatus_FIELDLIST(X, a) \
+X(a, STATIC, OPTIONAL, MESSAGE, status, 1)
+#define meshtastic_EthernetConnectionStatus_CALLBACK NULL
+#define meshtastic_EthernetConnectionStatus_DEFAULT NULL
+#define meshtastic_EthernetConnectionStatus_status_MSGTYPE meshtastic_NetworkConnectionStatus
+
+#define meshtastic_NetworkConnectionStatus_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, FIXED32, ip_address, 1) \
+X(a, STATIC, SINGULAR, BOOL, is_connected, 2) \
+X(a, STATIC, SINGULAR, BOOL, is_mqtt_connected, 3) \
+X(a, STATIC, SINGULAR, BOOL, is_syslog_connected, 4)
+#define meshtastic_NetworkConnectionStatus_CALLBACK NULL
+#define meshtastic_NetworkConnectionStatus_DEFAULT NULL
+
+#define meshtastic_BluetoothConnectionStatus_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, UINT32, pin, 1) \
+X(a, STATIC, SINGULAR, INT32, rssi, 2) \
+X(a, STATIC, SINGULAR, BOOL, is_connected, 3)
+#define meshtastic_BluetoothConnectionStatus_CALLBACK NULL
+#define meshtastic_BluetoothConnectionStatus_DEFAULT NULL
+
+#define meshtastic_SerialConnectionStatus_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, UINT32, baud, 1) \
+X(a, STATIC, SINGULAR, BOOL, is_connected, 2)
+#define meshtastic_SerialConnectionStatus_CALLBACK NULL
+#define meshtastic_SerialConnectionStatus_DEFAULT NULL
+
+extern const pb_msgdesc_t meshtastic_DeviceConnectionStatus_msg;
+extern const pb_msgdesc_t meshtastic_WifiConnectionStatus_msg;
+extern const pb_msgdesc_t meshtastic_EthernetConnectionStatus_msg;
+extern const pb_msgdesc_t meshtastic_NetworkConnectionStatus_msg;
+extern const pb_msgdesc_t meshtastic_BluetoothConnectionStatus_msg;
+extern const pb_msgdesc_t meshtastic_SerialConnectionStatus_msg;
+
+/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
+#define meshtastic_DeviceConnectionStatus_fields &meshtastic_DeviceConnectionStatus_msg
+#define meshtastic_WifiConnectionStatus_fields &meshtastic_WifiConnectionStatus_msg
+#define meshtastic_EthernetConnectionStatus_fields &meshtastic_EthernetConnectionStatus_msg
+#define meshtastic_NetworkConnectionStatus_fields &meshtastic_NetworkConnectionStatus_msg
+#define meshtastic_BluetoothConnectionStatus_fields &meshtastic_BluetoothConnectionStatus_msg
+#define meshtastic_SerialConnectionStatus_fields &meshtastic_SerialConnectionStatus_msg
+
+/* Maximum encoded size of messages (where known) */
+#define meshtastic_BluetoothConnectionStatus_size 19
+#define meshtastic_DeviceConnectionStatus_size 106
+#define meshtastic_EthernetConnectionStatus_size 13
+#define meshtastic_NetworkConnectionStatus_size 11
+#define meshtastic_SerialConnectionStatus_size 8
+#define meshtastic_WifiConnectionStatus_size 58
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/mesh/generated/meshtastic/device_metadata.pb.h b/src/mesh/generated/meshtastic/device_metadata.pb.h
index 384863601..44cf29079 100644
--- a/src/mesh/generated/meshtastic/device_metadata.pb.h
+++ b/src/mesh/generated/meshtastic/device_metadata.pb.h
@@ -5,6 +5,7 @@
#define PB_MESHTASTIC_MESHTASTIC_DEVICE_METADATA_PB_H_INCLUDED
#include
#include "meshtastic/config.pb.h"
+#include "meshtastic/mesh.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
@@ -29,6 +30,8 @@ typedef struct _meshtastic_DeviceMetadata {
meshtastic_Config_DeviceConfig_Role role;
/* Indicates the device's current enabled position flags */
uint32_t position_flags;
+ /* Device hardware model */
+ meshtastic_HardwareModel hw_model;
} meshtastic_DeviceMetadata;
@@ -37,8 +40,8 @@ extern "C" {
#endif
/* Initializer values for message structs */
-#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0}
-#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0}
+#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN}
+#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_DeviceMetadata_firmware_version_tag 1
@@ -49,6 +52,7 @@ extern "C" {
#define meshtastic_DeviceMetadata_hasEthernet_tag 6
#define meshtastic_DeviceMetadata_role_tag 7
#define meshtastic_DeviceMetadata_position_flags_tag 8
+#define meshtastic_DeviceMetadata_hw_model_tag 9
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceMetadata_FIELDLIST(X, a) \
@@ -59,7 +63,8 @@ X(a, STATIC, SINGULAR, BOOL, hasWifi, 4) \
X(a, STATIC, SINGULAR, BOOL, hasBluetooth, 5) \
X(a, STATIC, SINGULAR, BOOL, hasEthernet, 6) \
X(a, STATIC, SINGULAR, UENUM, role, 7) \
-X(a, STATIC, SINGULAR, UINT32, position_flags, 8)
+X(a, STATIC, SINGULAR, UINT32, position_flags, 8) \
+X(a, STATIC, SINGULAR, UENUM, hw_model, 9)
#define meshtastic_DeviceMetadata_CALLBACK NULL
#define meshtastic_DeviceMetadata_DEFAULT NULL
@@ -69,7 +74,7 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
#define meshtastic_DeviceMetadata_fields &meshtastic_DeviceMetadata_msg
/* Maximum encoded size of messages (where known) */
-#define meshtastic_DeviceMetadata_size 41
+#define meshtastic_DeviceMetadata_size 44
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h
index 842431b28..aef8ee8be 100644
--- a/src/mesh/generated/meshtastic/deviceonly.pb.h
+++ b/src/mesh/generated/meshtastic/deviceonly.pb.h
@@ -5,6 +5,7 @@
#define PB_MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_INCLUDED
#include
#include "meshtastic/channel.pb.h"
+#include "meshtastic/localonly.pb.h"
#include "meshtastic/mesh.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
@@ -85,6 +86,12 @@ typedef struct _meshtastic_OEMStore {
char oem_text[40];
/* The default device encryption key, 16 or 32 byte */
meshtastic_OEMStore_oem_aes_key_t oem_aes_key;
+ /* A Preset LocalConfig to apply during factory reset */
+ bool has_oem_local_config;
+ meshtastic_LocalConfig oem_local_config;
+ /* A Preset LocalModuleConfig to apply during factory reset */
+ bool has_oem_local_module_config;
+ meshtastic_LocalModuleConfig oem_local_module_config;
} meshtastic_OEMStore;
@@ -105,10 +112,10 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default, meshtastic_NodeInfo_init_default}, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0}
#define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0}
-#define meshtastic_OEMStore_init_default {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}}
+#define meshtastic_OEMStore_init_default {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default}
#define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero, meshtastic_NodeInfo_init_zero}, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0}
#define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0}
-#define meshtastic_OEMStore_init_zero {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}}
+#define meshtastic_OEMStore_init_zero {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}, false, meshtastic_LocalConfig_init_zero, false, meshtastic_LocalModuleConfig_init_zero}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_DeviceState_my_node_tag 2
@@ -127,6 +134,8 @@ extern "C" {
#define meshtastic_OEMStore_oem_font_tag 4
#define meshtastic_OEMStore_oem_text_tag 5
#define meshtastic_OEMStore_oem_aes_key_tag 6
+#define meshtastic_OEMStore_oem_local_config_tag 7
+#define meshtastic_OEMStore_oem_local_module_config_tag 8
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceState_FIELDLIST(X, a) \
@@ -159,9 +168,13 @@ X(a, STATIC, SINGULAR, UINT32, oem_icon_height, 2) \
X(a, STATIC, SINGULAR, BYTES, oem_icon_bits, 3) \
X(a, STATIC, SINGULAR, UENUM, oem_font, 4) \
X(a, STATIC, SINGULAR, STRING, oem_text, 5) \
-X(a, STATIC, SINGULAR, BYTES, oem_aes_key, 6)
+X(a, STATIC, SINGULAR, BYTES, oem_aes_key, 6) \
+X(a, STATIC, OPTIONAL, MESSAGE, oem_local_config, 7) \
+X(a, STATIC, OPTIONAL, MESSAGE, oem_local_module_config, 8)
#define meshtastic_OEMStore_CALLBACK NULL
#define meshtastic_OEMStore_DEFAULT NULL
+#define meshtastic_OEMStore_oem_local_config_MSGTYPE meshtastic_LocalConfig
+#define meshtastic_OEMStore_oem_local_module_config_MSGTYPE meshtastic_LocalModuleConfig
extern const pb_msgdesc_t meshtastic_DeviceState_msg;
extern const pb_msgdesc_t meshtastic_ChannelFile_msg;
@@ -175,7 +188,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_ChannelFile_size 638
#define meshtastic_DeviceState_size 21800
-#define meshtastic_OEMStore_size 2140
+#define meshtastic_OEMStore_size 2992
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/meshtastic/telemetry.pb.c b/src/mesh/generated/meshtastic/telemetry.pb.c
index cdc01710a..cbcac3e20 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_AirQualityMetrics, meshtastic_AirQualityMetrics, AUTO)
+
+
PB_BIND(meshtastic_Telemetry, meshtastic_Telemetry, AUTO)
diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h
index 188b27d77..6d4a5e1fc 100644
--- a/src/mesh/generated/meshtastic/telemetry.pb.h
+++ b/src/mesh/generated/meshtastic/telemetry.pb.h
@@ -10,7 +10,7 @@
#endif
/* Enum definitions */
-/* TODO: REPLACE */
+/* Supported I2C Sensors for telemetry in Meshtastic */
typedef enum _meshtastic_TelemetrySensorType {
/* No external telemetry sensor explicitly set */
meshtastic_TelemetrySensorType_SENSOR_UNSET = 0,
@@ -37,7 +37,9 @@ typedef enum _meshtastic_TelemetrySensorType {
/* 3-Axis magnetic sensor */
meshtastic_TelemetrySensorType_QMC5883L = 11,
/* High accuracy temperature and humidity */
- meshtastic_TelemetrySensorType_SHT31 = 12
+ meshtastic_TelemetrySensorType_SHT31 = 12,
+ /* PM2.5 air quality sensor */
+ meshtastic_TelemetrySensorType_PMSA003I = 13
} meshtastic_TelemetrySensorType;
/* Struct definitions */
@@ -69,6 +71,34 @@ typedef struct _meshtastic_EnvironmentMetrics {
float current;
} meshtastic_EnvironmentMetrics;
+/* Air quality metrics */
+typedef struct _meshtastic_AirQualityMetrics {
+ /* Standard PM1.0 */
+ uint32_t pm10_standard;
+ /* Standard PM2.5 */
+ uint32_t pm25_standard;
+ /* Standard PM10.0 */
+ uint32_t pm100_standard;
+ /* Environmental PM1.0 */
+ uint32_t pm10_environmental;
+ /* Environmental PM2.5 */
+ uint32_t pm25_environmental;
+ /* Environmental PM10.0 */
+ uint32_t pm100_environmental;
+ /* 0.3um Particle Count */
+ uint32_t particles_03um;
+ /* 0.5um Particle Count */
+ uint32_t particles_05um;
+ /* 1.0um Particle Count */
+ uint32_t particles_10um;
+ /* 2.5um Particle Count */
+ uint32_t particles_25um;
+ /* 5.0um Particle Count */
+ uint32_t particles_50um;
+ /* 10.0um Particle Count */
+ uint32_t particles_100um;
+} meshtastic_AirQualityMetrics;
+
/* Types of Measurements the telemetry module is equipped to handle */
typedef struct _meshtastic_Telemetry {
/* This is usually not sent over the mesh (to save space), but it is sent
@@ -83,6 +113,8 @@ typedef struct _meshtastic_Telemetry {
meshtastic_DeviceMetrics device_metrics;
/* Weather station or other environmental metrics */
meshtastic_EnvironmentMetrics environment_metrics;
+ /* Air quality metrics */
+ meshtastic_AirQualityMetrics air_quality_metrics;
} variant;
} meshtastic_Telemetry;
@@ -93,8 +125,9 @@ extern "C" {
/* Helper constants for enums */
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
-#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SHT31
-#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SHT31+1))
+#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_PMSA003I
+#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_PMSA003I+1))
+
@@ -103,9 +136,11 @@ 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_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_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}}
/* Field tags (for use in manual encoding/decoding) */
@@ -119,9 +154,22 @@ extern "C" {
#define meshtastic_EnvironmentMetrics_gas_resistance_tag 4
#define meshtastic_EnvironmentMetrics_voltage_tag 5
#define meshtastic_EnvironmentMetrics_current_tag 6
+#define meshtastic_AirQualityMetrics_pm10_standard_tag 1
+#define meshtastic_AirQualityMetrics_pm25_standard_tag 2
+#define meshtastic_AirQualityMetrics_pm100_standard_tag 3
+#define meshtastic_AirQualityMetrics_pm10_environmental_tag 4
+#define meshtastic_AirQualityMetrics_pm25_environmental_tag 5
+#define meshtastic_AirQualityMetrics_pm100_environmental_tag 6
+#define meshtastic_AirQualityMetrics_particles_03um_tag 7
+#define meshtastic_AirQualityMetrics_particles_05um_tag 8
+#define meshtastic_AirQualityMetrics_particles_10um_tag 9
+#define meshtastic_AirQualityMetrics_particles_25um_tag 10
+#define meshtastic_AirQualityMetrics_particles_50um_tag 11
+#define meshtastic_AirQualityMetrics_particles_100um_tag 12
#define meshtastic_Telemetry_time_tag 1
#define meshtastic_Telemetry_device_metrics_tag 2
#define meshtastic_Telemetry_environment_metrics_tag 3
+#define meshtastic_Telemetry_air_quality_metrics_tag 4
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceMetrics_FIELDLIST(X, a) \
@@ -142,28 +190,49 @@ X(a, STATIC, SINGULAR, FLOAT, current, 6)
#define meshtastic_EnvironmentMetrics_CALLBACK NULL
#define meshtastic_EnvironmentMetrics_DEFAULT NULL
+#define meshtastic_AirQualityMetrics_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, UINT32, pm10_standard, 1) \
+X(a, STATIC, SINGULAR, UINT32, pm25_standard, 2) \
+X(a, STATIC, SINGULAR, UINT32, pm100_standard, 3) \
+X(a, STATIC, SINGULAR, UINT32, pm10_environmental, 4) \
+X(a, STATIC, SINGULAR, UINT32, pm25_environmental, 5) \
+X(a, STATIC, SINGULAR, UINT32, pm100_environmental, 6) \
+X(a, STATIC, SINGULAR, UINT32, particles_03um, 7) \
+X(a, STATIC, SINGULAR, UINT32, particles_05um, 8) \
+X(a, STATIC, SINGULAR, UINT32, particles_10um, 9) \
+X(a, STATIC, SINGULAR, UINT32, particles_25um, 10) \
+X(a, STATIC, SINGULAR, UINT32, particles_50um, 11) \
+X(a, STATIC, SINGULAR, UINT32, particles_100um, 12)
+#define meshtastic_AirQualityMetrics_CALLBACK NULL
+#define meshtastic_AirQualityMetrics_DEFAULT NULL
+
#define meshtastic_Telemetry_FIELDLIST(X, a) \
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,environment_metrics,variant.environment_metrics), 3) \
+X(a, STATIC, ONEOF, MESSAGE, (variant,air_quality_metrics,variant.air_quality_metrics), 4)
#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
extern const pb_msgdesc_t meshtastic_DeviceMetrics_msg;
extern const pb_msgdesc_t meshtastic_EnvironmentMetrics_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_AirQualityMetrics_fields &meshtastic_AirQualityMetrics_msg
#define meshtastic_Telemetry_fields &meshtastic_Telemetry_msg
/* Maximum encoded size of messages (where known) */
+#define meshtastic_AirQualityMetrics_size 72
#define meshtastic_DeviceMetrics_size 21
#define meshtastic_EnvironmentMetrics_size 30
-#define meshtastic_Telemetry_size 37
+#define meshtastic_Telemetry_size 79
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index 18557f0b3..3c4cef829 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -2,17 +2,24 @@
#include "Channels.h"
#include "MeshService.h"
#include "NodeDB.h"
+#include "PowerFSM.h"
#ifdef ARCH_ESP32
#include "BleOta.h"
#endif
#include "Router.h"
#include "configuration.h"
#include "main.h"
-
+#ifdef ARCH_NRF52
+#include "main.h"
+#endif
#ifdef ARCH_PORTDUINO
#include "unistd.h"
#endif
+#if HAS_WIFI || HAS_ETHERNET
+#include "mqtt/MQTT.h"
+#endif
+
#define DEFAULT_REBOOT_SECONDS 5
AdminModule *adminModule;
@@ -99,6 +106,10 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
else
handleSetChannel(r->set_channel);
break;
+ case meshtastic_AdminMessage_set_ham_mode_tag:
+ LOG_INFO("Client is setting ham mode\n");
+ handleSetHamMode(r->set_ham_mode);
+ break;
/**
* Other
@@ -159,6 +170,11 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
saveChanges(SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
break;
}
+ case meshtastic_AdminMessage_get_device_connection_status_request_tag: {
+ LOG_INFO("Client is getting device connection status\n");
+ handleGetDeviceConnectionStatus(mp);
+ break;
+ }
#ifdef ARCH_PORTDUINO
case meshtastic_AdminMessage_exit_simulator_tag:
LOG_INFO("Exiting simulator\n");
@@ -487,12 +503,74 @@ void AdminModule::handleGetDeviceMetadata(const meshtastic_MeshPacket &req)
deviceMetadata.hasEthernet = HAS_ETHERNET;
deviceMetadata.role = config.device.role;
deviceMetadata.position_flags = config.position.position_flags;
+ deviceMetadata.hw_model = HW_VENDOR;
r.get_device_metadata_response = deviceMetadata;
r.which_payload_variant = meshtastic_AdminMessage_get_device_metadata_response_tag;
myReply = allocDataProtobuf(r);
}
+void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &req)
+{
+ meshtastic_AdminMessage r = meshtastic_AdminMessage_init_default;
+
+ meshtastic_DeviceConnectionStatus conn;
+
+ conn.wifi = {0};
+#if HAS_WIFI
+ conn.has_wifi = true;
+ conn.wifi.has_status = true;
+#ifdef ARCH_PORTDUINO
+ conn.wifi.status.is_connected = true;
+#else
+ conn.wifi.status.is_connected = WiFi.status() != WL_CONNECTED;
+#endif
+ strncpy(conn.wifi.ssid, config.network.wifi_ssid, 33);
+ if (conn.wifi.status.is_connected) {
+ conn.wifi.rssi = WiFi.RSSI();
+ conn.wifi.status.ip_address = WiFi.localIP();
+ conn.wifi.status.is_mqtt_connected = mqtt && mqtt->connected();
+ conn.wifi.status.is_syslog_connected = false; // FIXME wire this up
+ }
+#else
+ conn.has_wifi = false;
+#endif
+
+ conn.ethernet = {0};
+#if HAS_ETHERNET
+ conn.has_ethernet = true;
+ conn.ethernet.has_status = true;
+ if (Ethernet.linkStatus() == LinkON) {
+ conn.ethernet.status.is_connected = true;
+ conn.ethernet.status.ip_address = Ethernet.localIP();
+ conn.ethernet.status.is_mqtt_connected = mqtt && mqtt->connected();
+ conn.ethernet.status.is_syslog_connected = false; // FIXME wire this up
+ } else {
+ conn.ethernet.status.is_connected = false;
+ }
+#else
+ conn.has_ethernet = false;
+#endif
+
+#if HAS_BLUETOOTH
+ conn.has_bluetooth = true;
+ conn.bluetooth.pin = config.bluetooth.fixed_pin;
+#endif
+#ifdef ARCH_ESP32
+ conn.bluetooth.is_connected = nimbleBluetooth->isConnected();
+ conn.bluetooth.rssi = nimbleBluetooth->getRssi();
+#elif defined(ARCH_NRF52)
+ conn.bluetooth.is_connected = nrf52Bluetooth->isConnected();
+#endif
+ conn.has_serial = true; // No serial-less devices
+ conn.serial.is_connected = powerFSM.getState() == &stateSERIAL;
+ conn.serial.baud = SERIAL_BAUD;
+
+ r.get_device_connection_status_response = conn;
+ r.which_payload_variant = meshtastic_AdminMessage_get_device_connection_status_response_tag;
+ myReply = allocDataProtobuf(r);
+}
+
void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t channelIndex)
{
if (req.decoded.want_response) {
@@ -524,6 +602,18 @@ void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
}
}
+void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
+{
+ strncpy(owner.long_name, p.call_sign, sizeof(owner.long_name));
+ owner.is_licensed = true;
+ config.lora.override_duty_cycle = true;
+ config.lora.tx_power = p.tx_power;
+ config.lora.override_frequency = p.frequency;
+
+ service.reloadOwner(false);
+ service.reloadConfig(SEGMENT_CONFIG | SEGMENT_DEVICESTATE);
+}
+
AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_APP, &meshtastic_AdminMessage_msg)
{
// restrict to the admin channel for rx
diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h
index a0602b140..7170e61d6 100644
--- a/src/modules/AdminModule.h
+++ b/src/modules/AdminModule.h
@@ -1,5 +1,8 @@
#pragma once
#include "ProtobufModule.h"
+#ifdef ARCH_ESP32
+#include "mesh/http/WiFiAPClient.h"
+#endif
/**
* Admin module for admin messages
@@ -31,7 +34,7 @@ class AdminModule : public ProtobufModule
void handleGetModuleConfig(const meshtastic_MeshPacket &req, uint32_t configType);
void handleGetChannel(const meshtastic_MeshPacket &req, uint32_t channelIndex);
void handleGetDeviceMetadata(const meshtastic_MeshPacket &req);
-
+ void handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &req);
/**
* Setters
*/
@@ -40,6 +43,7 @@ class AdminModule : public ProtobufModule
void handleSetConfig(const meshtastic_Config &c);
void handleSetModuleConfig(const meshtastic_ModuleConfig &c);
void handleSetChannel();
+ void handleSetHamMode(const meshtastic_HamParameters &req);
void reboot(int32_t seconds);
};
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index e8481356b..bc874a9a3 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -14,6 +14,7 @@
#include "modules/TraceRouteModule.h"
#include "modules/WaypointModule.h"
#if HAS_TELEMETRY
+#include "modules/Telemetry/AirQualityTelemetry.h"
#include "modules/Telemetry/DeviceTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h"
#endif
@@ -63,6 +64,9 @@ void setupModules()
#if HAS_TELEMETRY
new DeviceTelemetryModule();
new EnvironmentTelemetryModule();
+ if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] > 0) {
+ new AirQualityTelemetryModule();
+ }
#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
new SerialModule();
diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp
new file mode 100644
index 000000000..2b744c489
--- /dev/null
+++ b/src/modules/Telemetry/AirQualityTelemetry.cpp
@@ -0,0 +1,128 @@
+#include "AirQualityTelemetry.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"
+
+int32_t AirQualityTelemetryModule::runOnce()
+{
+#ifndef ARCH_PORTDUINO
+ int32_t result = INT32_MAX;
+ /*
+ Uncomment the preferences below if you want to use the module
+ without having to configure it from the PythonAPI or WebUI.
+ */
+
+ // moduleConfig.telemetry.environment_measurement_enabled = 1;
+
+ if (!(moduleConfig.telemetry.environment_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 (moduleConfig.telemetry.environment_measurement_enabled) {
+ LOG_INFO("Air quality Telemetry: Initializing\n");
+ if (!aqi.begin_I2C()) {
+ LOG_WARN("Could not establish i2c connection to AQI sensor\n");
+ return disable();
+ }
+ return 1000;
+ }
+ return result;
+ } else {
+ // if we somehow got to a second run of this module with measurement disabled, then just wait forever
+ if (!moduleConfig.telemetry.environment_measurement_enabled)
+ return result;
+
+ uint32_t now = millis();
+ if (((lastSentToMesh == 0) ||
+ ((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) &&
+ airTime->isTxAllowedAirUtil()) {
+ sendTelemetry();
+ lastSentToMesh = now;
+ } else if (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);
+ }
+ }
+ return sendToPhoneIntervalMs;
+#endif
+}
+
+bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
+{
+ if (t->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) {
+ const char *sender = getSenderShortName(mp);
+
+ LOG_INFO("(Received from %s): pm10_standard=%i, pm25_standard=%i, pm100_standard=%i\n", sender,
+ t->variant.air_quality_metrics.pm10_standard, t->variant.air_quality_metrics.pm25_standard,
+ t->variant.air_quality_metrics.pm100_standard);
+
+ LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i\n",
+ t->variant.air_quality_metrics.pm10_environmental, t->variant.air_quality_metrics.pm25_environmental,
+ t->variant.air_quality_metrics.pm100_environmental);
+
+ // 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 AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
+{
+ if (!aqi.read(&data)) {
+ LOG_WARN("Skipping send measurements. Could not read AQIn\n");
+ return false;
+ }
+
+ meshtastic_Telemetry m;
+ m.time = getTime();
+ m.which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
+ m.variant.air_quality_metrics.pm10_standard = data.pm10_standard;
+ m.variant.air_quality_metrics.pm25_standard = data.pm25_standard;
+ m.variant.air_quality_metrics.pm100_standard = data.pm100_standard;
+
+ m.variant.air_quality_metrics.pm10_environmental = data.pm10_env;
+ m.variant.air_quality_metrics.pm25_environmental = data.pm25_env;
+ m.variant.air_quality_metrics.pm100_environmental = data.pm100_env;
+
+ LOG_INFO("(Sending): PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i\n",
+ m.variant.air_quality_metrics.pm10_standard, m.variant.air_quality_metrics.pm25_standard,
+ m.variant.air_quality_metrics.pm100_standard);
+
+ LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i\n",
+ m.variant.air_quality_metrics.pm10_environmental, m.variant.air_quality_metrics.pm25_environmental,
+ m.variant.air_quality_metrics.pm100_environmental);
+
+ meshtastic_MeshPacket *p = allocDataProtobuf(m);
+ p->to = dest;
+ p->decoded.want_response = false;
+ 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);
+ }
+ return true;
+}
diff --git a/src/modules/Telemetry/AirQualityTelemetry.h b/src/modules/Telemetry/AirQualityTelemetry.h
new file mode 100644
index 000000000..ab77d61e7
--- /dev/null
+++ b/src/modules/Telemetry/AirQualityTelemetry.h
@@ -0,0 +1,37 @@
+#pragma once
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "Adafruit_PM25AQI.h"
+#include "NodeDB.h"
+#include "ProtobufModule.h"
+
+class AirQualityTelemetryModule : private concurrency::OSThread, public ProtobufModule
+{
+ public:
+ AirQualityTelemetryModule()
+ : concurrency::OSThread("AirQualityTelemetryModule"),
+ ProtobufModule("AirQualityTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
+ {
+ lastMeasurementPacket = nullptr;
+ setIntervalFromNow(10 * 1000);
+ aqi = Adafruit_PM25AQI();
+ }
+
+ 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:
+ Adafruit_PM25AQI aqi;
+ PM25_AQI_Data data = {0};
+ bool firstTime = 1;
+ meshtastic_MeshPacket *lastMeasurementPacket;
+ uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
+ uint32_t lastSentToMesh = 0;
+};
diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp
index 630de2933..43c25b6a7 100644
--- a/src/modules/Telemetry/DeviceTelemetry.cpp
+++ b/src/modules/Telemetry/DeviceTelemetry.cpp
@@ -13,8 +13,8 @@
int32_t DeviceTelemetryModule::runOnce()
{
uint32_t now = millis();
- if ((lastSentToMesh == 0 ||
- (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval)) &&
+ if (((lastSentToMesh == 0) ||
+ ((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) &&
airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil()) {
sendTelemetry();
lastSentToMesh = now;
@@ -35,8 +35,6 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
t->variant.device_metrics.air_util_tx, t->variant.device_metrics.channel_utilization,
t->variant.device_metrics.battery_level, t->variant.device_metrics.voltage);
- lastMeasurementPacket = packetPool.allocCopy(mp);
-
nodeDB.updateTelemetry(getFrom(&mp), *t, RX_SRC_RADIO);
}
return false; // Let others look at this message also if they want
@@ -63,7 +61,6 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
p->decoded.want_response = false;
p->priority = meshtastic_MeshPacket_Priority_MIN;
- lastMeasurementPacket = packetPool.allocCopy(*p);
nodeDB.updateTelemetry(nodeDB.getNodeNum(), t, RX_SRC_LOCAL);
if (phoneOnly) {
LOG_INFO("Sending packet to phone\n");
diff --git a/src/modules/Telemetry/DeviceTelemetry.h b/src/modules/Telemetry/DeviceTelemetry.h
index 94641f04e..ba16e095a 100644
--- a/src/modules/Telemetry/DeviceTelemetry.h
+++ b/src/modules/Telemetry/DeviceTelemetry.h
@@ -12,7 +12,6 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu
: concurrency::OSThread("DeviceTelemetryModule"),
ProtobufModule("DeviceTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
{
- lastMeasurementPacket = nullptr;
setIntervalFromNow(10 * 1000);
}
virtual bool wantUIFrame() { return false; }
@@ -31,5 +30,4 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu
private:
uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
uint32_t lastSentToMesh = 0;
- const meshtastic_MeshPacket *lastMeasurementPacket;
};
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index ae4f9e648..d9b129e70 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -103,8 +103,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
return result;
uint32_t now = millis();
- if ((lastSentToMesh == 0 ||
- (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval)) &&
+ if (((lastSentToMesh == 0) ||
+ ((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();
lastSentToMesh = now;
@@ -118,6 +118,16 @@ int32_t EnvironmentTelemetryModule::runOnce()
#endif
}
+bool EnvironmentTelemetryModule::wantUIFrame()
+{
+ return moduleConfig.telemetry.environment_screen_enabled;
+}
+
+float EnvironmentTelemetryModule::CelsiusToFahrenheit(float c)
+{
+ return (c * 9) / 5 + 32;
+}
+
uint32_t GetTimeSinceMeshPacket(const meshtastic_MeshPacket *mp)
{
uint32_t now = getTime();
@@ -130,16 +140,6 @@ uint32_t GetTimeSinceMeshPacket(const meshtastic_MeshPacket *mp)
return delta;
}
-bool EnvironmentTelemetryModule::wantUIFrame()
-{
- return moduleConfig.telemetry.environment_screen_enabled;
-}
-
-float EnvironmentTelemetryModule::CelsiusToFahrenheit(float c)
-{
- return (c * 9) / 5 + 32;
-}
-
void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -193,6 +193,10 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
t->variant.environment_metrics.gas_resistance, t->variant.environment_metrics.relative_humidity,
t->variant.environment_metrics.temperature, t->variant.environment_metrics.voltage);
+ // release previous packet before occupying a new spot
+ if (lastMeasurementPacket != nullptr)
+ packetPool.release(lastMeasurementPacket);
+
lastMeasurementPacket = packetPool.allocCopy(mp);
}
@@ -244,6 +248,10 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
p->decoded.want_response = false;
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");
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h
index 69ef29edb..3340f8751 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.h
+++ b/src/modules/Telemetry/EnvironmentTelemetry.h
@@ -36,7 +36,7 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu
private:
float CelsiusToFahrenheit(float c);
bool firstTime = 1;
- const meshtastic_MeshPacket *lastMeasurementPacket;
+ meshtastic_MeshPacket *lastMeasurementPacket;
uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
uint32_t lastSentToMesh = 0;
uint32_t sensor_read_error_count = 0;
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index 221c69957..56bdf300f 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -19,9 +19,9 @@ const int reconnectMax = 5;
MQTT *mqtt;
-String statusTopic = "msh/2/stat/";
-String cryptTopic = "msh/2/c/"; // msh/2/c/CHANNELID/NODEID
-String jsonTopic = "msh/2/json/"; // msh/2/json/CHANNELID/NODEID
+std::string statusTopic = "msh/2/stat/";
+std::string cryptTopic = "msh/2/c/"; // msh/2/c/CHANNELID/NODEID
+std::string jsonTopic = "msh/2/json/"; // msh/2/json/CHANNELID/NODEID
static MemoryDynamic staticMqttPool;
@@ -238,11 +238,11 @@ void MQTT::sendSubscriptions()
for (size_t i = 0; i < numChan; i++) {
auto &ch = channels.getByIndex(i);
if (ch.settings.downlink_enabled) {
- String topic = cryptTopic + channels.getGlobalId(i) + "/#";
+ std::string topic = cryptTopic + channels.getGlobalId(i) + "/#";
LOG_INFO("Subscribing to %s\n", topic.c_str());
pubSub.subscribe(topic.c_str(), 1); // FIXME, is QOS 1 right?
if (moduleConfig.mqtt.json_enabled == true) {
- String topicDecoded = jsonTopic + channels.getGlobalId(i) + "/#";
+ std::string topicDecoded = jsonTopic + channels.getGlobalId(i) + "/#";
LOG_INFO("Subscribing to %s\n", topicDecoded.c_str());
pubSub.subscribe(topicDecoded.c_str(), 1); // FIXME, is QOS 1 right?
}
@@ -296,7 +296,7 @@ int32_t MQTT::runOnce()
static uint8_t bytes[meshtastic_MeshPacket_size + 64];
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env);
- String topic = cryptTopic + env->channel_id + "/" + owner.id;
+ std::string topic = cryptTopic + env->channel_id + "/" + owner.id;
LOG_INFO("publish %s, %u bytes from queue\n", topic.c_str(), numBytes);
pubSub.publish(topic.c_str(), bytes, numBytes, false);
@@ -305,7 +305,7 @@ int32_t MQTT::runOnce()
// handle json topic
auto jsonString = this->downstreamPacketToJson(env->packet);
if (jsonString.length() != 0) {
- String topicJson = jsonTopic + env->channel_id + "/" + owner.id;
+ std::string topicJson = jsonTopic + env->channel_id + "/" + owner.id;
LOG_INFO("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(),
jsonString.c_str());
pubSub.publish(topicJson.c_str(), jsonString.c_str(), false);
@@ -350,7 +350,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex)
static uint8_t bytes[meshtastic_MeshPacket_size + 64];
size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, env);
- String topic = cryptTopic + channelId + "/" + owner.id;
+ std::string topic = cryptTopic + channelId + "/" + owner.id;
LOG_DEBUG("publish %s, %u bytes\n", topic.c_str(), numBytes);
pubSub.publish(topic.c_str(), bytes, numBytes, false);
@@ -359,7 +359,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex)
// handle json topic
auto jsonString = this->downstreamPacketToJson((meshtastic_MeshPacket *)&mp);
if (jsonString.length() != 0) {
- String topicJson = jsonTopic + channelId + "/" + owner.id;
+ std::string topicJson = jsonTopic + channelId + "/" + owner.id;
LOG_INFO("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(),
jsonString.c_str());
pubSub.publish(topicJson.c_str(), jsonString.c_str(), false);
@@ -386,7 +386,7 @@ std::string MQTT::downstreamPacketToJson(meshtastic_MeshPacket *mp)
{
// the created jsonObj is immutable after creation, so
// we need to do the heavy lifting before assembling it.
- String msgType;
+ std::string msgType;
JSONObject msgPayload;
JSONObject jsonObj;
diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp
index 79be9a35b..1f06b25f2 100644
--- a/src/nimble/NimbleBluetooth.cpp
+++ b/src/nimble/NimbleBluetooth.cpp
@@ -93,7 +93,6 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
passkeyShowing = false;
screen->stopBluetoothPinScreen();
}
- // bluetoothPhoneAPI->setInitialState();
}
virtual void onDisconnect(NimBLEServer *pServer, ble_gap_conn_desc *desc) { LOG_INFO("BLE disconnect\n"); }
@@ -117,6 +116,21 @@ bool NimbleBluetooth::isActive()
return bleServer;
}
+bool NimbleBluetooth::isConnected()
+{
+ return bleServer->getConnectedCount() > 0;
+}
+
+int NimbleBluetooth::getRssi()
+{
+ if (bleServer && isConnected()) {
+ auto service = bleServer->getServiceByUUID(MESH_SERVICE_UUID);
+ uint16_t handle = service->getHandle();
+ return NimBLEDevice::getClientByID(handle)->getRssi();
+ }
+ return 0; // FIXME figure out where to source this
+}
+
void NimbleBluetooth::setup()
{
// Uncomment for testing
@@ -135,7 +149,6 @@ void NimbleBluetooth::setup()
NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback();
bleServer->setCallbacks(serverCallbacks, true);
-
setupService();
startAdvertising();
}
diff --git a/src/nimble/NimbleBluetooth.h b/src/nimble/NimbleBluetooth.h
index ec0fe0841..4080a7cbc 100644
--- a/src/nimble/NimbleBluetooth.h
+++ b/src/nimble/NimbleBluetooth.h
@@ -1,12 +1,15 @@
#pragma once
+#include "BluetoothCommon.h"
-class NimbleBluetooth
+class NimbleBluetooth : BluetoothApi
{
public:
void setup();
void shutdown();
void clearBonds();
bool isActive();
+ bool isConnected();
+ int getRssi();
private:
void setupService();
diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp
index ca757a6e5..f6bd4f50e 100644
--- a/src/platform/esp32/main-esp32.cpp
+++ b/src/platform/esp32/main-esp32.cpp
@@ -19,11 +19,9 @@
#include
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
-NimbleBluetooth *nimbleBluetooth;
void setBluetoothEnable(bool on)
{
-
if (!isWifiAvailable() && config.bluetooth.enabled == true) {
if (!nimbleBluetooth) {
nimbleBluetooth = new NimbleBluetooth();
diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp
index 06b07f593..044b57ae6 100644
--- a/src/platform/nrf52/NRF52Bluetooth.cpp
+++ b/src/platform/nrf52/NRF52Bluetooth.cpp
@@ -213,6 +213,16 @@ void NRF52Bluetooth::shutdown()
Bluefruit.Advertising.stop();
}
+bool NRF52Bluetooth::isConnected()
+{
+ return Bluefruit.connected(connectionHandle);
+}
+
+int NRF52Bluetooth::getRssi()
+{
+ return 0; // FIXME figure out where to source this
+}
+
void NRF52Bluetooth::setup()
{
// Initialise the Bluefruit module
diff --git a/src/platform/nrf52/NRF52Bluetooth.h b/src/platform/nrf52/NRF52Bluetooth.h
index b4438ff39..193e86cf8 100644
--- a/src/platform/nrf52/NRF52Bluetooth.h
+++ b/src/platform/nrf52/NRF52Bluetooth.h
@@ -1,13 +1,16 @@
#pragma once
+#include "BluetoothCommon.h"
#include
-class NRF52Bluetooth
+class NRF52Bluetooth : BluetoothApi
{
public:
void setup();
void shutdown();
void clearBonds();
+ bool isConnected();
+ int getRssi();
private:
static void onConnectionSecured(uint16_t conn_handle);
diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp
index 0384073a4..1cbe05631 100644
--- a/src/platform/nrf52/main-nrf52.cpp
+++ b/src/platform/nrf52/main-nrf52.cpp
@@ -8,9 +8,8 @@
#include
// #include
#include "NodeDB.h"
-
-#include "NRF52Bluetooth.h"
#include "error.h"
+#include "main.h"
#ifdef BQ25703A_ADDR
#include "BQ25713.h"
@@ -63,8 +62,6 @@ static void initBrownout()
// We don't bother with setting up brownout if soft device is disabled - because during production we always use softdevice
}
-NRF52Bluetooth *nrf52Bluetooth;
-
static bool bleOn = false;
static const bool useSoftDevice = true; // Set to false for easier debugging
diff --git a/src/platform/rp2040/rp2040CryptoEngine.cpp b/src/platform/rp2040/rp2040CryptoEngine.cpp
index bb1c00779..c90126cc7 100644
--- a/src/platform/rp2040/rp2040CryptoEngine.cpp
+++ b/src/platform/rp2040/rp2040CryptoEngine.cpp
@@ -1,6 +1,6 @@
-#include "configuration.h"
#include "CryptoEngine.h"
#include "aes.hpp"
+#include "configuration.h"
class RP2040CryptoEngine : public CryptoEngine
{
diff --git a/version.properties b/version.properties
index f68474788..78d9518bf 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 0
-build = 18
+build = 19