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..4c6bc9bfa 100644 --- a/platformio.ini +++ b/platformio.ini @@ -113,6 +113,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..59a67810c 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 6290ee0f6aa15939ee582c3c59bc7a048cc0478f +Subproject commit 59a67810ca07b731839cf1b44b142778fa55b5bf diff --git a/src/configuration.h b/src/configuration.h index 2640b1572..b6b272097 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 @@ -205,4 +206,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/main.cpp b/src/main.cpp index 9b7d811c4..a18ee4099 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -502,6 +502,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) 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/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 0d2238396..4b4072dcc 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: @@ -546,4 +546,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) sendingPacket = p; return p->encrypted.size + sizeof(PacketHeader); -} +} \ No newline at end of file diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 9c5d66293..85ce116dc 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -56,7 +56,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); @@ -223,4 +223,4 @@ class RadioInterface }; /// Debug printing for packets -void printPacket(const char *prefix, const meshtastic_MeshPacket *p); +void printPacket(const char *prefix, const meshtastic_MeshPacket *p); \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index c554074a2..56924bb82 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -316,7 +316,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg; #define meshtastic_DeviceState_size 16854 #define meshtastic_NodeInfoLite_size 151 #define meshtastic_NodeRemoteHardwarePin_size 29 -#define meshtastic_OEMStore_size 3218 +#define meshtastic_OEMStore_size 3230 #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 f672d865c..fe9c9e70a 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 463 -#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..fc1221a83 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -378,6 +378,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 +528,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/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 1e0e8250d..05105c05c 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] @@ -39,7 +39,7 @@ uint8_t blue = 0; /* Documentation: - https://meshtastic.org/docs/settings/moduleconfig/external-notification + https://meshtastic.org/docs/configuration/module/external-notification */ // Default configurations 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/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