mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Merge branch 'ripplebiz:dev' into dev
This commit is contained in:
commit
77bfc0db1c
24 changed files with 451 additions and 197 deletions
|
|
@ -19,6 +19,7 @@ struct NodePrefs { // persisted to file
|
||||||
uint8_t tx_power_dbm;
|
uint8_t tx_power_dbm;
|
||||||
uint8_t telemetry_mode_base;
|
uint8_t telemetry_mode_base;
|
||||||
uint8_t telemetry_mode_loc;
|
uint8_t telemetry_mode_loc;
|
||||||
|
uint8_t telemetry_mode_env;
|
||||||
float rx_delay_base;
|
float rx_delay_base;
|
||||||
uint32_t ble_pin;
|
uint32_t ble_pin;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,29 @@ void UITask::begin(DisplayDriver* display, NodePrefs* node_prefs, const char* bu
|
||||||
|
|
||||||
// v1.2.3 (1 Jan 2025)
|
// v1.2.3 (1 Jan 2025)
|
||||||
sprintf(_version_info, "%s (%s)", version, build_date);
|
sprintf(_version_info, "%s (%s)", version, build_date);
|
||||||
|
|
||||||
|
#ifdef PIN_BUZZER
|
||||||
|
buzzer.begin();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void UITask::soundBuzzer(UIEventType bet) {
|
||||||
|
#if defined(PIN_BUZZER)
|
||||||
|
switch(bet){
|
||||||
|
case UIEventType::contactMessage:
|
||||||
|
// gemini's pick
|
||||||
|
buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
|
||||||
|
break;
|
||||||
|
case UIEventType::channelMessage:
|
||||||
|
case UIEventType::roomMessage:
|
||||||
|
case UIEventType::newContactMessage:
|
||||||
|
case UIEventType::none:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// Serial.print("DBG: Buzzzzzz -> ");
|
||||||
|
// Serial.println((int) bet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::msgRead(int msgcount) {
|
void UITask::msgRead(int msgcount) {
|
||||||
|
|
@ -248,6 +271,10 @@ void UITask::loop() {
|
||||||
buttonHandler();
|
buttonHandler();
|
||||||
userLedHandler();
|
userLedHandler();
|
||||||
|
|
||||||
|
#ifdef PIN_BUZZER
|
||||||
|
if (buzzer.isPlaying()) buzzer.loop();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (_display != NULL && _display->isOn()) {
|
if (_display != NULL && _display->isOn()) {
|
||||||
static bool _firstBoot = true;
|
static bool _firstBoot = true;
|
||||||
if(_firstBoot && millis() >= BOOT_SCREEN_MILLIS) {
|
if(_firstBoot && millis() >= BOOT_SCREEN_MILLIS) {
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,27 @@
|
||||||
#include <helpers/ui/DisplayDriver.h>
|
#include <helpers/ui/DisplayDriver.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef PIN_BUZZER
|
||||||
|
#include <helpers/ui/buzzer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "NodePrefs.h"
|
#include "NodePrefs.h"
|
||||||
|
|
||||||
|
enum class UIEventType
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
contactMessage,
|
||||||
|
channelMessage,
|
||||||
|
roomMessage,
|
||||||
|
newContactMessage
|
||||||
|
};
|
||||||
|
|
||||||
class UITask {
|
class UITask {
|
||||||
DisplayDriver* _display;
|
DisplayDriver* _display;
|
||||||
mesh::MainBoard* _board;
|
mesh::MainBoard* _board;
|
||||||
|
#ifdef PIN_BUZZER
|
||||||
|
genericBuzzer buzzer;
|
||||||
|
#endif
|
||||||
unsigned long _next_refresh, _auto_off;
|
unsigned long _next_refresh, _auto_off;
|
||||||
bool _connected;
|
bool _connected;
|
||||||
uint32_t _pin_code;
|
uint32_t _pin_code;
|
||||||
|
|
@ -24,6 +40,7 @@ class UITask {
|
||||||
void userLedHandler();
|
void userLedHandler();
|
||||||
void renderBatteryIndicator(uint16_t batteryMilliVolts);
|
void renderBatteryIndicator(uint16_t batteryMilliVolts);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
UITask(mesh::MainBoard* board) : _board(board), _display(NULL) {
|
UITask(mesh::MainBoard* board) : _board(board), _display(NULL) {
|
||||||
|
|
@ -37,5 +54,6 @@ public:
|
||||||
void clearMsgPreview();
|
void clearMsgPreview();
|
||||||
void msgRead(int msgcount);
|
void msgRead(int msgcount);
|
||||||
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount);
|
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount);
|
||||||
|
void soundBuzzer(UIEventType bet = UIEventType::none);
|
||||||
void loop();
|
void loop();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -271,8 +271,8 @@ class MyMesh : public BaseChatMesh {
|
||||||
|
|
||||||
void saveContacts() {
|
void saveContacts() {
|
||||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||||
|
_fs->remove("/contacts3");
|
||||||
File file = _fs->open("/contacts3", FILE_O_WRITE);
|
File file = _fs->open("/contacts3", FILE_O_WRITE);
|
||||||
if (file) { file.seek(0); file.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File file = _fs->open("/contacts3", "w");
|
File file = _fs->open("/contacts3", "w");
|
||||||
#else
|
#else
|
||||||
|
|
@ -336,8 +336,8 @@ class MyMesh : public BaseChatMesh {
|
||||||
|
|
||||||
void saveChannels() {
|
void saveChannels() {
|
||||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||||
|
_fs->remove("/channels2");
|
||||||
File file = _fs->open("/channels2", FILE_O_WRITE);
|
File file = _fs->open("/channels2", FILE_O_WRITE);
|
||||||
if (file) { file.seek(0); file.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File file = _fs->open("/channels2", "w");
|
File file = _fs->open("/channels2", "w");
|
||||||
#else
|
#else
|
||||||
|
|
@ -393,8 +393,8 @@ class MyMesh : public BaseChatMesh {
|
||||||
sprintf(path, "/bl/%s", fname);
|
sprintf(path, "/bl/%s", fname);
|
||||||
|
|
||||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||||
|
_fs->remove(path);
|
||||||
File f = _fs->open(path, FILE_O_WRITE);
|
File f = _fs->open(path, FILE_O_WRITE);
|
||||||
if (f) { f.seek(0); f.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File f = _fs->open(path, "w");
|
File f = _fs->open(path, "w");
|
||||||
#else
|
#else
|
||||||
|
|
@ -483,10 +483,6 @@ class MyMesh : public BaseChatMesh {
|
||||||
return 0; // queue is empty
|
return 0; // queue is empty
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundBuzzer() {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float getAirtimeBudgetFactor() const override {
|
float getAirtimeBudgetFactor() const override {
|
||||||
return _prefs.airtime_factor;
|
return _prefs.airtime_factor;
|
||||||
|
|
@ -523,7 +519,9 @@ protected:
|
||||||
_serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE);
|
_serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
soundBuzzer();
|
#ifdef DISPLAY_CLASS
|
||||||
|
ui_task.soundBuzzer(UIEventType::newContactMessage);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
saveContacts();
|
saveContacts();
|
||||||
|
|
@ -584,7 +582,9 @@ protected:
|
||||||
frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle'
|
frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle'
|
||||||
_serial->writeFrame(frame, 1);
|
_serial->writeFrame(frame, 1);
|
||||||
} else {
|
} else {
|
||||||
soundBuzzer();
|
#ifdef DISPLAY_CLASS
|
||||||
|
ui_task.soundBuzzer(UIEventType::contactMessage);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
ui_task.newMsg(path_len, from.name, text, offline_queue_len);
|
ui_task.newMsg(path_len, from.name, text, offline_queue_len);
|
||||||
|
|
@ -635,7 +635,9 @@ protected:
|
||||||
frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle'
|
frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle'
|
||||||
_serial->writeFrame(frame, 1);
|
_serial->writeFrame(frame, 1);
|
||||||
} else {
|
} else {
|
||||||
soundBuzzer();
|
#ifdef DISPLAY_CLASS
|
||||||
|
ui_task.soundBuzzer(UIEventType::channelMessage);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
ui_task.newMsg(path_len, "Public", text, offline_queue_len);
|
ui_task.newMsg(path_len, "Public", text, offline_queue_len);
|
||||||
|
|
@ -659,6 +661,12 @@ protected:
|
||||||
permissions |= cp & TELEM_PERM_LOCATION;
|
permissions |= cp & TELEM_PERM_LOCATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) {
|
||||||
|
permissions |= TELEM_PERM_ENVIRONMENT;
|
||||||
|
} else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) {
|
||||||
|
permissions |= cp & TELEM_PERM_ENVIRONMENT;
|
||||||
|
}
|
||||||
|
|
||||||
if (permissions & TELEM_PERM_BASE) { // only respond if base permission bit is set
|
if (permissions & TELEM_PERM_BASE) { // only respond if base permission bit is set
|
||||||
telemetry.reset();
|
telemetry.reset();
|
||||||
telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
|
telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
|
||||||
|
|
@ -822,7 +830,7 @@ public:
|
||||||
file.read((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
|
file.read((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
|
||||||
file.read((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69
|
file.read((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69
|
||||||
file.read((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
|
file.read((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
|
||||||
file.read(pad, 1); // 71
|
file.read((uint8_t *) &_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
|
||||||
file.read((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
|
file.read((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
|
||||||
file.read(pad, 4); // 76
|
file.read(pad, 4); // 76
|
||||||
file.read((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
|
file.read((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
|
||||||
|
|
@ -861,6 +869,11 @@ public:
|
||||||
mesh::Utils::toHex(pub_key_hex, self_id.pub_key, 4);
|
mesh::Utils::toHex(pub_key_hex, self_id.pub_key, 4);
|
||||||
strcpy(_prefs.node_name, pub_key_hex);
|
strcpy(_prefs.node_name, pub_key_hex);
|
||||||
|
|
||||||
|
// if name is provided as a build flag, use that as default node name instead
|
||||||
|
#ifdef ADVERT_NAME
|
||||||
|
strcpy(_prefs.node_name, ADVERT_NAME);
|
||||||
|
#endif
|
||||||
|
|
||||||
// load persisted prefs
|
// load persisted prefs
|
||||||
if (_fs->exists("/new_prefs")) {
|
if (_fs->exists("/new_prefs")) {
|
||||||
loadPrefsInt("/new_prefs"); // new filename
|
loadPrefsInt("/new_prefs"); // new filename
|
||||||
|
|
@ -913,8 +926,8 @@ public:
|
||||||
|
|
||||||
void savePrefs() {
|
void savePrefs() {
|
||||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||||
|
_fs->remove("/new_prefs");
|
||||||
File file = _fs->open("/new_prefs", FILE_O_WRITE);
|
File file = _fs->open("/new_prefs", FILE_O_WRITE);
|
||||||
if (file) { file.seek(0); file.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File file = _fs->open("/new_prefs", "w");
|
File file = _fs->open("/new_prefs", "w");
|
||||||
#else
|
#else
|
||||||
|
|
@ -938,7 +951,7 @@ public:
|
||||||
file.write((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
|
file.write((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
|
||||||
file.write((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69
|
file.write((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69
|
||||||
file.write((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
|
file.write((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
|
||||||
file.write(pad, 1); // 71
|
file.write((uint8_t *) &_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
|
||||||
file.write((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
|
file.write((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
|
||||||
file.write(pad, 4); // 76
|
file.write(pad, 4); // 76
|
||||||
file.write((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
|
file.write((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
|
||||||
|
|
@ -983,7 +996,7 @@ public:
|
||||||
memcpy(&out_frame[i], &lon, 4); i += 4;
|
memcpy(&out_frame[i], &lon, 4); i += 4;
|
||||||
out_frame[i++] = 0; // reserved
|
out_frame[i++] = 0; // reserved
|
||||||
out_frame[i++] = 0; // reserved
|
out_frame[i++] = 0; // reserved
|
||||||
out_frame[i++] = (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+
|
out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+
|
||||||
out_frame[i++] = _prefs.manual_add_contacts;
|
out_frame[i++] = _prefs.manual_add_contacts;
|
||||||
|
|
||||||
uint32_t freq = _prefs.freq * 1000;
|
uint32_t freq = _prefs.freq * 1000;
|
||||||
|
|
@ -1275,6 +1288,7 @@ public:
|
||||||
if (len >= 3) {
|
if (len >= 3) {
|
||||||
_prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+
|
_prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+
|
||||||
_prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03;
|
_prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03;
|
||||||
|
_prefs.telemetry_mode_env = (cmd_frame[2] >> 4) & 0x03;
|
||||||
}
|
}
|
||||||
savePrefs();
|
savePrefs();
|
||||||
writeOKFrame();
|
writeOKFrame();
|
||||||
|
|
|
||||||
|
|
@ -127,8 +127,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor {
|
||||||
|
|
||||||
void saveContacts() {
|
void saveContacts() {
|
||||||
#if defined(NRF52_PLATFORM)
|
#if defined(NRF52_PLATFORM)
|
||||||
|
_fs->remove("/contacts");
|
||||||
File file = _fs->open("/contacts", FILE_O_WRITE);
|
File file = _fs->open("/contacts", FILE_O_WRITE);
|
||||||
if (file) { file.seek(0); file.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File file = _fs->open("/contacts", "w");
|
File file = _fs->open("/contacts", "w");
|
||||||
#else
|
#else
|
||||||
|
|
@ -341,8 +341,8 @@ public:
|
||||||
|
|
||||||
void savePrefs() {
|
void savePrefs() {
|
||||||
#if defined(NRF52_PLATFORM)
|
#if defined(NRF52_PLATFORM)
|
||||||
|
_fs->remove("/node_prefs");
|
||||||
File file = _fs->open("/node_prefs", FILE_O_WRITE);
|
File file = _fs->open("/node_prefs", FILE_O_WRITE);
|
||||||
if (file) { file.seek(0); file.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File file = _fs->open("/node_prefs", "w");
|
File file = _fs->open("/node_prefs", "w");
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,8 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||||
|
|
||||||
void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
||||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||||
|
fs->remove("/com_prefs");
|
||||||
File file = fs->open("/com_prefs", FILE_O_WRITE);
|
File file = fs->open("/com_prefs", FILE_O_WRITE);
|
||||||
if (file) { file.seek(0); file.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File file = fs->open("/com_prefs", "w");
|
File file = fs->open("/com_prefs", "w");
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id) {
|
||||||
sprintf(filename, "%s/%s.id", _dir, name);
|
sprintf(filename, "%s/%s.id", _dir, name);
|
||||||
|
|
||||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||||
|
_fs->remove(filename);
|
||||||
File file = _fs->open(filename, FILE_O_WRITE);
|
File file = _fs->open(filename, FILE_O_WRITE);
|
||||||
if (file) { file.seek(0); file.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File file = _fs->open(filename, "w");
|
File file = _fs->open(filename, "w");
|
||||||
#else
|
#else
|
||||||
|
|
@ -69,8 +69,8 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id, const
|
||||||
sprintf(filename, "%s/%s.id", _dir, name);
|
sprintf(filename, "%s/%s.id", _dir, name);
|
||||||
|
|
||||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||||
|
_fs->remove(filename);
|
||||||
File file = _fs->open(filename, FILE_O_WRITE);
|
File file = _fs->open(filename, FILE_O_WRITE);
|
||||||
if (file) { file.seek(0); file.truncate(); }
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
File file = _fs->open(filename, "w");
|
File file = _fs->open(filename, "w");
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
90
src/helpers/sensors/EnvironmentSensorManager.cpp
Normal file
90
src/helpers/sensors/EnvironmentSensorManager.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
#include "EnvironmentSensorManager.h"
|
||||||
|
|
||||||
|
static Adafruit_AHTX0 AHTX0;
|
||||||
|
static Adafruit_BME280 BME280;
|
||||||
|
static Adafruit_INA3221 INA3221;
|
||||||
|
static Adafruit_INA219 INA219(TELEM_INA219_ADDRESS);
|
||||||
|
|
||||||
|
bool EnvironmentSensorManager::begin() {
|
||||||
|
|
||||||
|
if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) {
|
||||||
|
MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS);
|
||||||
|
MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID());
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; i++) {
|
||||||
|
INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE);
|
||||||
|
}
|
||||||
|
INA3221_initialized = true;
|
||||||
|
} else {
|
||||||
|
INA3221_initialized = false;
|
||||||
|
MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INA219.begin(&Wire)) {
|
||||||
|
MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS);
|
||||||
|
INA219_initialized = true;
|
||||||
|
} else {
|
||||||
|
INA219_initialized = false;
|
||||||
|
MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AHTX0.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) {
|
||||||
|
MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS);
|
||||||
|
AHTX0_initialized = true;
|
||||||
|
} else {
|
||||||
|
AHTX0_initialized = false;
|
||||||
|
MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BME280.begin(TELEM_BME280_ADDRESS, &Wire)) {
|
||||||
|
MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS);
|
||||||
|
MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID);
|
||||||
|
BME280_initialized = true;
|
||||||
|
} else {
|
||||||
|
BME280_initialized = false;
|
||||||
|
MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
|
||||||
|
next_available_channel = TELEM_CHANNEL_SELF + 1;
|
||||||
|
if (requester_permissions & TELEM_PERM_ENVIRONMENT) {
|
||||||
|
if (INA3221_initialized) {
|
||||||
|
for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) {
|
||||||
|
// add only enabled INA3221 channels to telemetry
|
||||||
|
if (INA3221.isChannelEnabled(i)) {
|
||||||
|
float voltage = INA3221.getBusVoltage(i);
|
||||||
|
float current = INA3221.getCurrentAmps(i);
|
||||||
|
telemetry.addVoltage(next_available_channel, voltage);
|
||||||
|
telemetry.addCurrent(next_available_channel, current);
|
||||||
|
telemetry.addPower(next_available_channel, voltage * current);
|
||||||
|
next_available_channel++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (INA219_initialized) {
|
||||||
|
telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V());
|
||||||
|
telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000);
|
||||||
|
telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000);
|
||||||
|
next_available_channel++;
|
||||||
|
}
|
||||||
|
if (AHTX0_initialized) {
|
||||||
|
sensors_event_t humidity, temp;
|
||||||
|
AHTX0.getEvent(&humidity, &temp);
|
||||||
|
|
||||||
|
telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature);
|
||||||
|
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BME280_initialized) {
|
||||||
|
telemetry.addTemperature(TELEM_CHANNEL_SELF, BME280.readTemperature());
|
||||||
|
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME280.readHumidity());
|
||||||
|
telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME280.readPressure());
|
||||||
|
telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280.readAltitude(TELEM_BME280_SEALEVELPRESSURE_HPA));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
32
src/helpers/sensors/EnvironmentSensorManager.h
Normal file
32
src/helpers/sensors/EnvironmentSensorManager.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <helpers/SensorManager.h>
|
||||||
|
#include <Mesh.h>
|
||||||
|
#include <Adafruit_INA3221.h>
|
||||||
|
#include <Adafruit_INA219.h>
|
||||||
|
#include <Adafruit_AHTX0.h>
|
||||||
|
#include <Adafruit_BME280.h>
|
||||||
|
|
||||||
|
#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address
|
||||||
|
#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address
|
||||||
|
#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address
|
||||||
|
#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address
|
||||||
|
|
||||||
|
#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts
|
||||||
|
#define TELEM_INA3221_NUM_CHANNELS 3
|
||||||
|
|
||||||
|
#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level
|
||||||
|
|
||||||
|
class EnvironmentSensorManager : public SensorManager {
|
||||||
|
protected:
|
||||||
|
int next_available_channel = TELEM_CHANNEL_SELF + 1;
|
||||||
|
|
||||||
|
bool INA3221_initialized = false;
|
||||||
|
bool INA219_initialized = false;
|
||||||
|
bool BME280_initialized = false;
|
||||||
|
bool AHTX0_initialized = false;
|
||||||
|
public:
|
||||||
|
EnvironmentSensorManager(){};
|
||||||
|
bool begin() override;
|
||||||
|
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
|
||||||
|
};
|
||||||
54
src/helpers/ui/buzzer.cpp
Normal file
54
src/helpers/ui/buzzer.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifdef PIN_BUZZER
|
||||||
|
#include "buzzer.h"
|
||||||
|
|
||||||
|
void genericBuzzer::begin() {
|
||||||
|
// Serial.print("DBG: Setting up buzzer on pin ");
|
||||||
|
// Serial.println(PIN_BUZZER);
|
||||||
|
#ifdef PIN_BUZZER_EN
|
||||||
|
pinMode(PIN_BUZZER_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_BUZZER_EN, HIGH);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
quiet(false);
|
||||||
|
pinMode(PIN_BUZZER, OUTPUT);
|
||||||
|
startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void genericBuzzer::play(const char *melody) {
|
||||||
|
if (isPlaying()) // interrupt existing
|
||||||
|
{
|
||||||
|
rtttl::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_is_quiet) return;
|
||||||
|
|
||||||
|
rtttl::begin(PIN_BUZZER,melody);
|
||||||
|
// Serial.print("DBG: Playing melody - isQuiet: ");
|
||||||
|
// Serial.println(isQuiet());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool genericBuzzer::isPlaying() {
|
||||||
|
return rtttl::isPlaying();
|
||||||
|
}
|
||||||
|
|
||||||
|
void genericBuzzer::loop() {
|
||||||
|
if (!rtttl::done()) rtttl::play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void genericBuzzer::startup() {
|
||||||
|
play(startup_song);
|
||||||
|
}
|
||||||
|
|
||||||
|
void genericBuzzer::shutdown() {
|
||||||
|
play(shutdown_song);
|
||||||
|
}
|
||||||
|
|
||||||
|
void genericBuzzer::quiet(bool buzzer_state) {
|
||||||
|
_is_quiet = buzzer_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool genericBuzzer::isQuiet() {
|
||||||
|
return _is_quiet;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ifdef PIN_BUZZER
|
||||||
37
src/helpers/ui/buzzer.h
Normal file
37
src/helpers/ui/buzzer.h
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <NonBlockingRtttl.h>
|
||||||
|
|
||||||
|
/* class abstracts underlying RTTTL library
|
||||||
|
|
||||||
|
Just a simple imlementation to start. At the moment use same
|
||||||
|
melody for message and discovery
|
||||||
|
Suggest enum type for different sounds
|
||||||
|
- on message
|
||||||
|
- on discovery
|
||||||
|
|
||||||
|
TODO
|
||||||
|
- make message ring tone configurable
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
class genericBuzzer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void begin(); // set up buzzer port
|
||||||
|
void play(const char *melody); // Generic play function
|
||||||
|
void loop(); // loop driven-nonblocking
|
||||||
|
void startup(); // play startup sound
|
||||||
|
void shutdown(); // play shutdown sound
|
||||||
|
bool isPlaying(); // returns true if a sound is still playing else false
|
||||||
|
void quiet(bool buzzer_state); // enables or disables the buzzer
|
||||||
|
bool isQuiet(); // get buzzer state on/off
|
||||||
|
|
||||||
|
private:
|
||||||
|
// gemini's picks:
|
||||||
|
const char *startup_song = "Startup:d=4,o=5,b=160:16c6,16e6,8g6";
|
||||||
|
const char *shutdown_song = "Shutdown:d=4,o=5,b=100:8g5,16e5,16c5";
|
||||||
|
|
||||||
|
bool _is_quiet = true;
|
||||||
|
};
|
||||||
|
|
@ -7,6 +7,7 @@ build_flags =
|
||||||
-D LILYGO_TBEAM
|
-D LILYGO_TBEAM
|
||||||
-D RADIO_CLASS=CustomSX1276
|
-D RADIO_CLASS=CustomSX1276
|
||||||
-D WRAPPER_CLASS=CustomSX1276Wrapper
|
-D WRAPPER_CLASS=CustomSX1276Wrapper
|
||||||
|
-D SX127X_CURRENT_LIMIT=120
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
-D P_LORA_TX_LED=4
|
-D P_LORA_TX_LED=4
|
||||||
-D PIN_BOARD_SDA=21
|
-D PIN_BOARD_SDA=21
|
||||||
|
|
@ -31,8 +32,6 @@ build_flags =
|
||||||
-D BLE_PIN_CODE=123456
|
-D BLE_PIN_CODE=123456
|
||||||
-D BLE_DEBUG_LOGGING=1
|
-D BLE_DEBUG_LOGGING=1
|
||||||
-D OFFLINE_QUEUE_SIZE=256
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
; -D MESH_PACKET_LOGGING=1
|
|
||||||
; -D MESH_DEBUG=1
|
|
||||||
; -D RADIOLIB_DEBUG_BASIC=1
|
; -D RADIOLIB_DEBUG_BASIC=1
|
||||||
; -D ENABLE_PRIVATE_KEY_IMPORT=1
|
; -D ENABLE_PRIVATE_KEY_IMPORT=1
|
||||||
; -D ENABLE_PRIVATE_KEY_EXPORT=1
|
; -D ENABLE_PRIVATE_KEY_EXPORT=1
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ build_flags =
|
||||||
-D DISPLAY_CLASS=SH1106Display
|
-D DISPLAY_CLASS=SH1106Display
|
||||||
-D SX126X_CURRENT_LIMIT=140
|
-D SX126X_CURRENT_LIMIT=140
|
||||||
-D SX126X_RX_BOOSTED_GAIN=1
|
-D SX126X_RX_BOOSTED_GAIN=1
|
||||||
|
-D SX126X_CURRENT_LIMIT=140
|
||||||
build_src_filter = ${esp32_base.build_src_filter}
|
build_src_filter = ${esp32_base.build_src_filter}
|
||||||
+<../variants/lilygo_tbeam_supreme_SX1262>
|
+<../variants/lilygo_tbeam_supreme_SX1262>
|
||||||
+<helpers/ui/SH1106Display.cpp>
|
+<helpers/ui/SH1106Display.cpp>
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,10 @@ void NanoG2Ultra::begin()
|
||||||
// for future use, sub-classes SHOULD call this from their begin()
|
// for future use, sub-classes SHOULD call this from their begin()
|
||||||
startup_reason = BD_STARTUP_NORMAL;
|
startup_reason = BD_STARTUP_NORMAL;
|
||||||
|
|
||||||
|
// set user button
|
||||||
pinMode(PIN_BUTTON1, INPUT);
|
pinMode(PIN_BUTTON1, INPUT);
|
||||||
|
|
||||||
// the external notification circuit is shared for both buzzer and led
|
// the external notification circuit is shared for both buzzer and led
|
||||||
// need to find out the switch state or somehow write a function that can
|
|
||||||
// sound the buzzer or signal the led. the led will stay on once brought HIGH
|
|
||||||
// and can be then brought LOW. It turns off with a hardware btn.
|
|
||||||
pinMode(EXT_NOTIFY_OUT, OUTPUT);
|
pinMode(EXT_NOTIFY_OUT, OUTPUT);
|
||||||
digitalWrite(EXT_NOTIFY_OUT, LOW);
|
digitalWrite(EXT_NOTIFY_OUT, LOW);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ build_flags =
|
||||||
-D BLE_DEBUG_LOGGING=1
|
-D BLE_DEBUG_LOGGING=1
|
||||||
-D OFFLINE_QUEUE_SIZE=256
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
-D DISPLAY_CLASS=SH1106Display
|
-D DISPLAY_CLASS=SH1106Display
|
||||||
|
-D PIN_BUZZER=4
|
||||||
; -D ENABLE_PRIVATE_KEY_IMPORT=1
|
; -D ENABLE_PRIVATE_KEY_IMPORT=1
|
||||||
; -D ENABLE_PRIVATE_KEY_EXPORT=1
|
; -D ENABLE_PRIVATE_KEY_EXPORT=1
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
|
|
@ -47,10 +48,12 @@ build_flags =
|
||||||
build_src_filter = ${Nano_G2_Ultra.build_src_filter}
|
build_src_filter = ${Nano_G2_Ultra.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
+<helpers/ui/SH1106Display.cpp>
|
+<helpers/ui/SH1106Display.cpp>
|
||||||
|
+<helpers/ui/buzzer.cpp>
|
||||||
+<../examples/companion_radio>
|
+<../examples/companion_radio>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${Nano_G2_Ultra.lib_deps}
|
${Nano_G2_Ultra.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
adafruit/Adafruit SH110X @ ~2.1.13
|
adafruit/Adafruit SH110X @ ~2.1.13
|
||||||
adafruit/Adafruit GFX Library @ ^1.12.1
|
adafruit/Adafruit GFX Library @ ^1.12.1
|
||||||
|
stevemarple/MicroNMEA @ ^2.0.6
|
||||||
|
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include <helpers/ArduinoHelpers.h>
|
#include <helpers/ArduinoHelpers.h>
|
||||||
|
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||||
|
|
||||||
NanoG2Ultra board;
|
NanoG2Ultra board;
|
||||||
|
|
||||||
|
|
@ -10,10 +11,11 @@ WRAPPER_CLASS radio_driver(radio, board);
|
||||||
|
|
||||||
VolatileRTCClock fallback_clock;
|
VolatileRTCClock fallback_clock;
|
||||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||||
SensorManager sensors;
|
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
|
||||||
|
NanoG2UltraSensorManager sensors = NanoG2UltraSensorManager(nmea);
|
||||||
|
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
DISPLAY_CLASS display;
|
DISPLAY_CLASS display;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LORA_CR
|
#ifndef LORA_CR
|
||||||
|
|
@ -73,6 +75,107 @@ void radio_set_tx_power(uint8_t dbm)
|
||||||
radio.setOutputPower(dbm);
|
radio.setOutputPower(dbm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NanoG2UltraSensorManager::start_gps()
|
||||||
|
{
|
||||||
|
if (!gps_active)
|
||||||
|
{
|
||||||
|
MESH_DEBUG_PRINTLN("starting GPS");
|
||||||
|
digitalWrite(PIN_GPS_STANDBY, HIGH);
|
||||||
|
gps_active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NanoG2UltraSensorManager::stop_gps()
|
||||||
|
{
|
||||||
|
if (gps_active)
|
||||||
|
{
|
||||||
|
MESH_DEBUG_PRINTLN("stopping GPS");
|
||||||
|
digitalWrite(PIN_GPS_STANDBY, LOW);
|
||||||
|
gps_active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NanoG2UltraSensorManager::begin()
|
||||||
|
{
|
||||||
|
Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX); // be sure to tx into rx and rx into tx
|
||||||
|
Serial1.begin(115200);
|
||||||
|
|
||||||
|
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_STANDBY, HIGH); // Wake GPS from standby
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
// We'll consider GPS detected if we see any data on Serial1
|
||||||
|
if (Serial1.available() > 0)
|
||||||
|
{
|
||||||
|
MESH_DEBUG_PRINTLN("GPS detected");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MESH_DEBUG_PRINTLN("No GPS detected");
|
||||||
|
}
|
||||||
|
digitalWrite(GPS_EN, LOW); // Put GPS back into standby mode
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NanoG2UltraSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP &telemetry)
|
||||||
|
{
|
||||||
|
if (requester_permissions & TELEM_PERM_LOCATION)
|
||||||
|
{ // does requester have permission?
|
||||||
|
telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NanoG2UltraSensorManager::loop()
|
||||||
|
{
|
||||||
|
static long next_gps_update = 0;
|
||||||
|
_location->loop();
|
||||||
|
if (millis() > next_gps_update && gps_active) // don't bother if gps position is not enabled
|
||||||
|
{
|
||||||
|
if (_location->isValid())
|
||||||
|
{
|
||||||
|
node_lat = ((double)_location->getLatitude()) / 1000000.;
|
||||||
|
node_lon = ((double)_location->getLongitude()) / 1000000.;
|
||||||
|
node_altitude = ((double)_location->getAltitude()) / 1000.0;
|
||||||
|
MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon);
|
||||||
|
}
|
||||||
|
next_gps_update = millis() + (1000 * 60); // after initial update, only check every minute TODO: should be configurable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int NanoG2UltraSensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch)
|
||||||
|
|
||||||
|
const char *NanoG2UltraSensorManager::getSettingName(int i) const
|
||||||
|
{
|
||||||
|
return i == 0 ? "gps" : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *NanoG2UltraSensorManager::getSettingValue(int i) const
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
return gps_active ? "1" : "0";
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NanoG2UltraSensorManager::setSettingValue(const char *name, const char *value)
|
||||||
|
{
|
||||||
|
if (strcmp(name, "gps") == 0)
|
||||||
|
{
|
||||||
|
if (strcmp(value, "0") == 0)
|
||||||
|
{
|
||||||
|
stop_gps();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
start_gps();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false; // not supported
|
||||||
|
}
|
||||||
|
|
||||||
mesh::LocalIdentity radio_new_identity()
|
mesh::LocalIdentity radio_new_identity()
|
||||||
{
|
{
|
||||||
RadioNoiseListener rng(radio);
|
RadioNoiseListener rng(radio);
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,36 @@
|
||||||
#include <helpers/AutoDiscoverRTCClock.h>
|
#include <helpers/AutoDiscoverRTCClock.h>
|
||||||
#include <helpers/SensorManager.h>
|
#include <helpers/SensorManager.h>
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
#include <helpers/ui/SH1106Display.h>
|
#include <helpers/ui/SH1106Display.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <helpers/sensors/LocationProvider.h>
|
||||||
|
|
||||||
|
class NanoG2UltraSensorManager : public SensorManager
|
||||||
|
{
|
||||||
|
bool gps_active = false;
|
||||||
|
LocationProvider *_location;
|
||||||
|
|
||||||
|
void start_gps();
|
||||||
|
void stop_gps();
|
||||||
|
|
||||||
|
public:
|
||||||
|
NanoG2UltraSensorManager(LocationProvider &location) : _location(&location) {}
|
||||||
|
bool begin() override;
|
||||||
|
bool querySensors(uint8_t requester_permissions, CayenneLPP &telemetry) override;
|
||||||
|
void loop() override;
|
||||||
|
int getNumSettings() const override;
|
||||||
|
const char *getSettingName(int i) const override;
|
||||||
|
const char *getSettingValue(int i) const override;
|
||||||
|
bool setSettingValue(const char *name, const char *value) override;
|
||||||
|
};
|
||||||
|
|
||||||
extern NanoG2Ultra board;
|
extern NanoG2Ultra board;
|
||||||
extern WRAPPER_CLASS radio_driver;
|
extern WRAPPER_CLASS radio_driver;
|
||||||
extern AutoDiscoverRTCClock rtc_clock;
|
extern AutoDiscoverRTCClock rtc_clock;
|
||||||
extern SensorManager sensors;
|
extern NanoG2UltraSensorManager sensors;
|
||||||
|
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
extern DISPLAY_CLASS display;
|
extern DISPLAY_CLASS display;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool radio_init();
|
bool radio_init();
|
||||||
|
|
|
||||||
|
|
@ -130,11 +130,15 @@ External serial flash W25Q16JV_IQ
|
||||||
* GPS pins
|
* GPS pins
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define HAS_GPS 1
|
||||||
#define GPS_L76K
|
#define GPS_L76K
|
||||||
|
|
||||||
#define PIN_GPS_STANDBY (0 + 13) // An output to wake GPS, low means allow sleep, high means force wake STANDBY
|
#define PIN_GPS_STANDBY (0 + 13) // An output to wake GPS, low means allow sleep, high means force wake STANDBY
|
||||||
#define PIN_GPS_TX (0 + 9) // This is for bits going TOWARDS the CPU
|
#define PIN_GPS_TX (0 + 9) // This is for bits going TOWARDS the CPU
|
||||||
#define PIN_GPS_RX (0 + 10) // This is for bits going TOWARDS the GPS
|
#define PIN_GPS_RX (0 + 10) // This is for bits going TOWARDS the GPS
|
||||||
|
#define GPS_RX_PIN PIN_GPS_RX
|
||||||
|
#define GPS_TX_PIN PIN_GPS_TX
|
||||||
|
|
||||||
|
|
||||||
// #define GPS_THREAD_INTERVAL 50
|
// #define GPS_THREAD_INTERVAL 50
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,14 @@ build_flags = ${nrf52840_base.build_flags}
|
||||||
-D PIN_USER_BTN=6
|
-D PIN_USER_BTN=6
|
||||||
build_src_filter = ${nrf52840_base.build_src_filter}
|
build_src_filter = ${nrf52840_base.build_src_filter}
|
||||||
+<helpers/nrf52/PromicroBoard.cpp>
|
+<helpers/nrf52/PromicroBoard.cpp>
|
||||||
|
+<helpers/sensors>
|
||||||
+<../variants/promicro>
|
+<../variants/promicro>
|
||||||
lib_deps= ${nrf52840_base.lib_deps}
|
lib_deps= ${nrf52840_base.lib_deps}
|
||||||
adafruit/Adafruit SSD1306 @ ^2.5.13
|
adafruit/Adafruit SSD1306 @ ^2.5.13
|
||||||
robtillaart/INA3221 @ ^0.4.1
|
adafruit/Adafruit INA3221 Library @ ^1.0.1
|
||||||
robtillaart/INA219 @ ^0.4.1
|
adafruit/Adafruit INA219 @ ^1.2.3
|
||||||
adafruit/Adafruit AHTX0@^2.0.5
|
adafruit/Adafruit AHTX0 @ ^2.0.5
|
||||||
|
adafruit/Adafruit BME280 Library @ ^2.3.0
|
||||||
|
|
||||||
[env:Faketec_Repeater]
|
[env:Faketec_Repeater]
|
||||||
extends = Faketec
|
extends = Faketec
|
||||||
|
|
@ -120,11 +122,13 @@ build_flags = ${nrf52840_base.build_flags}
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${nrf52840_base.build_src_filter}
|
${nrf52840_base.build_src_filter}
|
||||||
+<helpers/nrf52/PromicroBoard.cpp>
|
+<helpers/nrf52/PromicroBoard.cpp>
|
||||||
|
+<helpers/sensors>
|
||||||
+<../variants/promicro>
|
+<../variants/promicro>
|
||||||
lib_deps= ${nrf52840_base.lib_deps}
|
lib_deps= ${nrf52840_base.lib_deps}
|
||||||
robtillaart/INA3221 @ ^0.4.1
|
adafruit/Adafruit INA3221 Library @ ^1.0.1
|
||||||
robtillaart/INA219 @ ^0.4.1
|
adafruit/Adafruit INA219 @ ^1.2.3
|
||||||
adafruit/Adafruit AHTX0@^2.0.5
|
adafruit/Adafruit AHTX0 @ ^2.0.5
|
||||||
|
adafruit/Adafruit BME280 Library @ ^2.3.0
|
||||||
|
|
||||||
[env:ProMicroLLCC68_Repeater]
|
[env:ProMicroLLCC68_Repeater]
|
||||||
extends = ProMicroLLCC68
|
extends = ProMicroLLCC68
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ WRAPPER_CLASS radio_driver(radio, board);
|
||||||
|
|
||||||
VolatileRTCClock fallback_clock;
|
VolatileRTCClock fallback_clock;
|
||||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||||
PromicroSensorManager sensors;
|
EnvironmentSensorManager sensors;
|
||||||
|
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
DISPLAY_CLASS display;
|
DISPLAY_CLASS display;
|
||||||
|
|
@ -79,120 +79,3 @@ mesh::LocalIdentity radio_new_identity() {
|
||||||
return mesh::LocalIdentity(&rng); // create new random identity
|
return mesh::LocalIdentity(&rng); // create new random identity
|
||||||
}
|
}
|
||||||
|
|
||||||
static INA3221 INA_3221(TELEM_INA3221_ADDRESS, &Wire);
|
|
||||||
static INA219 INA_219(TELEM_INA219_ADDRESS, &Wire);
|
|
||||||
static Adafruit_AHTX0 AHTX;
|
|
||||||
|
|
||||||
bool PromicroSensorManager::begin() {
|
|
||||||
initINA3221();
|
|
||||||
initINA219();
|
|
||||||
initAHTX();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PromicroSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
|
|
||||||
int nextAvalableChannel = TELEM_CHANNEL_SELF + 1;
|
|
||||||
if (requester_permissions & TELEM_PERM_ENVIRONMENT) {
|
|
||||||
if (INA3221initialized) {
|
|
||||||
for(int i = 0; i < 3; i++) {
|
|
||||||
// add only enabled INA3221 channels to telemetry
|
|
||||||
if (INA3221_CHANNEL_ENABLED[i]) {
|
|
||||||
telemetry.addVoltage(nextAvalableChannel, INA_3221.getBusVoltage(i));
|
|
||||||
telemetry.addCurrent(nextAvalableChannel, INA_3221.getCurrent(i));
|
|
||||||
telemetry.addPower(nextAvalableChannel, INA_3221.getPower(i));
|
|
||||||
nextAvalableChannel++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (INA219initialized) {
|
|
||||||
telemetry.addVoltage(nextAvalableChannel, INA_219.getBusVoltage());
|
|
||||||
telemetry.addCurrent(nextAvalableChannel, INA_219.getCurrent());
|
|
||||||
telemetry.addPower(nextAvalableChannel, INA_219.getPower());
|
|
||||||
nextAvalableChannel++;
|
|
||||||
}
|
|
||||||
if (AHTXinitialized) {
|
|
||||||
sensors_event_t humidity, temp;
|
|
||||||
AHTX.getEvent(&humidity, &temp);
|
|
||||||
telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature);
|
|
||||||
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PromicroSensorManager::getNumSettings() const {
|
|
||||||
return NUM_SENSOR_SETTINGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* PromicroSensorManager::getSettingName(int i) const {
|
|
||||||
if (i >= 0 && i < NUM_SENSOR_SETTINGS) {
|
|
||||||
return INA3221_CHANNEL_NAMES[i];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* PromicroSensorManager::getSettingValue(int i) const {
|
|
||||||
if (i >= 0 && i < NUM_SENSOR_SETTINGS) {
|
|
||||||
return INA3221_CHANNEL_ENABLED[i] ? "1" : "0";
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PromicroSensorManager::setSettingValue(const char* name, const char* value) {
|
|
||||||
for (int i = 0; i < NUM_SENSOR_SETTINGS; i++) {
|
|
||||||
if (strcmp(name, INA3221_CHANNEL_NAMES[i]) == 0) {
|
|
||||||
int channelEnabled = INA_3221.getEnableChannel(i);
|
|
||||||
if (strcmp(value, "1") == 0) {
|
|
||||||
INA3221_CHANNEL_ENABLED[i] = true;
|
|
||||||
if (!channelEnabled) {
|
|
||||||
INA_3221.enableChannel(i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
INA3221_CHANNEL_ENABLED[i] = false;
|
|
||||||
if (channelEnabled) {
|
|
||||||
INA_3221.disableChannel(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PromicroSensorManager::initINA3221() {
|
|
||||||
if (INA_3221.begin()) {
|
|
||||||
MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", INA_3221.getAddress());
|
|
||||||
MESH_DEBUG_PRINTLN("%04X %04X %04X", INA_3221.getDieID(), INA_3221.getManufacturerID(), INA_3221.getConfiguration());
|
|
||||||
|
|
||||||
for(int i = 0; i < 3; i++) {
|
|
||||||
INA_3221.setShuntR(i, TELEM_INA3221_SHUNT_VALUE);
|
|
||||||
}
|
|
||||||
INA3221initialized = true;
|
|
||||||
} else {
|
|
||||||
INA3221initialized = false;
|
|
||||||
MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PromicroSensorManager::initINA219() {
|
|
||||||
if (INA_219.begin()) {
|
|
||||||
MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", INA_219.getAddress());
|
|
||||||
INA_219.setMaxCurrentShunt(TELEM_INA219_MAX_CURRENT, TELEM_INA219_SHUNT_VALUE);
|
|
||||||
INA219initialized = true;
|
|
||||||
} else {
|
|
||||||
INA219initialized = false;
|
|
||||||
MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PromicroSensorManager::initAHTX() {
|
|
||||||
if (AHTX.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) {
|
|
||||||
MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS);
|
|
||||||
AHTXinitialized = true;
|
|
||||||
} else {
|
|
||||||
AHTXinitialized = false;
|
|
||||||
MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,16 @@
|
||||||
#include <helpers/CustomSX1262Wrapper.h>
|
#include <helpers/CustomSX1262Wrapper.h>
|
||||||
#include <helpers/CustomLLCC68Wrapper.h>
|
#include <helpers/CustomLLCC68Wrapper.h>
|
||||||
#include <helpers/AutoDiscoverRTCClock.h>
|
#include <helpers/AutoDiscoverRTCClock.h>
|
||||||
#include <helpers/SensorManager.h>
|
|
||||||
#include <INA3221.h>
|
|
||||||
#include <INA219.h>
|
|
||||||
#include <Adafruit_AHTX0.h>
|
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
#include <helpers/ui/SSD1306Display.h>
|
#include <helpers/ui/SSD1306Display.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NUM_SENSOR_SETTINGS 3
|
#include <helpers/sensors/EnvironmentSensorManager.h>
|
||||||
|
|
||||||
extern PromicroBoard board;
|
extern PromicroBoard board;
|
||||||
extern WRAPPER_CLASS radio_driver;
|
extern WRAPPER_CLASS radio_driver;
|
||||||
extern AutoDiscoverRTCClock rtc_clock;
|
extern AutoDiscoverRTCClock rtc_clock;
|
||||||
|
extern EnvironmentSensorManager sensors;
|
||||||
|
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
extern DISPLAY_CLASS display;
|
extern DISPLAY_CLASS display;
|
||||||
|
|
@ -31,39 +28,3 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
|
||||||
void radio_set_tx_power(uint8_t dbm);
|
void radio_set_tx_power(uint8_t dbm);
|
||||||
mesh::LocalIdentity radio_new_identity();
|
mesh::LocalIdentity radio_new_identity();
|
||||||
|
|
||||||
#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address
|
|
||||||
#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address
|
|
||||||
#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address
|
|
||||||
|
|
||||||
#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts
|
|
||||||
#define TELEM_INA3221_SETTING_CH1 "INA3221-1"
|
|
||||||
#define TELEM_INA3221_SETTING_CH2 "INA3221-2"
|
|
||||||
#define TELEM_INA3221_SETTING_CH3 "INA3221-3"
|
|
||||||
|
|
||||||
#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers)
|
|
||||||
#define TELEM_INA219_MAX_CURRENT 5
|
|
||||||
|
|
||||||
class PromicroSensorManager: public SensorManager {
|
|
||||||
bool INA3221initialized = false;
|
|
||||||
bool INA219initialized = false;
|
|
||||||
bool AHTXinitialized = false;
|
|
||||||
|
|
||||||
// INA3221 channels in telemetry
|
|
||||||
const char * INA3221_CHANNEL_NAMES[NUM_SENSOR_SETTINGS] = { TELEM_INA3221_SETTING_CH1, TELEM_INA3221_SETTING_CH2, TELEM_INA3221_SETTING_CH3};
|
|
||||||
bool INA3221_CHANNEL_ENABLED[NUM_SENSOR_SETTINGS] = {true, true, true};
|
|
||||||
|
|
||||||
void initINA3221();
|
|
||||||
void initINA219();
|
|
||||||
void initAHTX();
|
|
||||||
public:
|
|
||||||
PromicroSensorManager(){};
|
|
||||||
bool begin() override;
|
|
||||||
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
|
|
||||||
int getNumSettings() const override;
|
|
||||||
const char* getSettingName(int i) const override;
|
|
||||||
const char* getSettingValue(int i) const override;
|
|
||||||
bool setSettingValue(const char* name, const char* value) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
extern PromicroSensorManager sensors;
|
|
||||||
|
|
@ -47,9 +47,13 @@ build_flags = ${t1000-e.build_flags}
|
||||||
-D RX_BOOSTED_GAIN=true
|
-D RX_BOOSTED_GAIN=true
|
||||||
-D RF_SWITCH_TABLE
|
-D RF_SWITCH_TABLE
|
||||||
-D DISPLAY_CLASS=NullDisplayDriver
|
-D DISPLAY_CLASS=NullDisplayDriver
|
||||||
|
-D PIN_BUZZER=25
|
||||||
|
-D PIN_BUZZER_EN=37 ; P1/5 - required for T1000-E
|
||||||
build_src_filter = ${t1000-e.build_src_filter}
|
build_src_filter = ${t1000-e.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
|
+<helpers/ui/buzzer.cpp>
|
||||||
+<../examples/companion_radio/*.cpp>
|
+<../examples/companion_radio/*.cpp>
|
||||||
lib_deps = ${t1000-e.lib_deps}
|
lib_deps = ${t1000-e.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
stevemarple/MicroNMEA @ ^2.0.6
|
stevemarple/MicroNMEA @ ^2.0.6
|
||||||
|
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||||
|
|
@ -97,7 +97,7 @@ bool T114SensorManager::begin() {
|
||||||
digitalWrite(GPS_EN, HIGH); // Power on GPS
|
digitalWrite(GPS_EN, HIGH); // Power on GPS
|
||||||
|
|
||||||
// Give GPS a moment to power up and send data
|
// Give GPS a moment to power up and send data
|
||||||
delay(500);
|
delay(1500);
|
||||||
|
|
||||||
// We'll consider GPS detected if we see any data on Serial1
|
// We'll consider GPS detected if we see any data on Serial1
|
||||||
gps_detected = (Serial1.available() > 0);
|
gps_detected = (Serial1.available() > 0);
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Buzzer
|
// Buzzer
|
||||||
|
|
||||||
#define PIN_BUZZER (46)
|
// #define PIN_BUZZER (46)
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue