mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-08-02 18:26:11 +00:00
feat: sensor placeholders in messages and keyboard picker
expandMsg now expands {temp}, {hum}, {pres}, {batt}, {alt}, {lux}, {dist},
{co2} from live sensor readings. The [{}] picker in the on-screen keyboard
shows only sensors currently detected by SensorManager and scrolls when
more than 3 items fit the overlay.
New SensorPlaceholders.h helper keeps sensor-to-keyboard wiring out of
UITask.cpp. MsgExpand.h handles all expansion logic centrally; MyMeshBot
and QuickMsgScreen pass &sensors and batt_volts to each call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
26d3d7ab00
commit
42b51935b1
@@ -3,26 +3,83 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <helpers/SensorManager.h>
|
||||||
|
#include <helpers/sensors/LPPDataHelpers.h>
|
||||||
|
|
||||||
// Expands {loc} and {time} placeholders in tmpl into out (out_len bytes).
|
// Expands placeholders in tmpl into out (out_len bytes).
|
||||||
// lat/lon — GPS coordinates; gps_valid must be true for {loc} to show coords
|
// {loc} — GPS coordinates (lat/lon) or "no GPS"
|
||||||
// utc_ts — unix timestamp from RTC (0 or <1e9 = no valid time)
|
// {time} — local time HH:MM from RTC
|
||||||
// tz_hours — local timezone offset from UTC (-12..+14)
|
// {temp} — temperature in °C (requires sm)
|
||||||
|
// {hum} — relative humidity % (requires sm)
|
||||||
|
// {pres} — barometric pressure hPa (requires sm)
|
||||||
|
// {batt} — battery voltage V (batt_volts >= 0 or LPP_VOLTAGE from sm)
|
||||||
|
// {alt} — altitude m (requires sm)
|
||||||
|
// {lux} — luminosity lux (requires sm)
|
||||||
|
// {dist} — distance m (requires sm)
|
||||||
|
// {co2} — CO2 concentration ppm (requires sm)
|
||||||
inline void expandMsg(const char* tmpl, char* out, int out_len,
|
inline void expandMsg(const char* tmpl, char* out, int out_len,
|
||||||
double lat, double lon, bool gps_valid,
|
double lat, double lon, bool gps_valid,
|
||||||
uint32_t utc_ts, int8_t tz_hours) {
|
uint32_t utc_ts, int8_t tz_hours,
|
||||||
|
SensorManager* sm = nullptr,
|
||||||
|
float batt_volts = -1.0f) {
|
||||||
|
// sv indices: 0=temp 1=hum 2=pres 3=batt 4=alt 5=lux 6=dist 7=co2
|
||||||
|
float sv[8] = {};
|
||||||
|
bool sv_ok[8] = {};
|
||||||
|
|
||||||
|
if (sm) {
|
||||||
|
CayenneLPP lpp(100);
|
||||||
|
sm->querySensors(0xFF, lpp);
|
||||||
|
LPPReader r(lpp.getBuffer(), lpp.getSize());
|
||||||
|
uint8_t ch, type;
|
||||||
|
while (r.readHeader(ch, type)) {
|
||||||
|
float tmp;
|
||||||
|
switch (type) {
|
||||||
|
case LPP_TEMPERATURE:
|
||||||
|
r.readTemperature(tmp);
|
||||||
|
if (!sv_ok[0]) { sv[0] = tmp; sv_ok[0] = true; } break;
|
||||||
|
case LPP_RELATIVE_HUMIDITY:
|
||||||
|
r.readRelativeHumidity(tmp);
|
||||||
|
if (!sv_ok[1]) { sv[1] = tmp; sv_ok[1] = true; } break;
|
||||||
|
case LPP_BAROMETRIC_PRESSURE:
|
||||||
|
r.readPressure(tmp);
|
||||||
|
if (!sv_ok[2]) { sv[2] = tmp; sv_ok[2] = true; } break;
|
||||||
|
case LPP_VOLTAGE:
|
||||||
|
r.readVoltage(tmp);
|
||||||
|
if (!sv_ok[3]) { sv[3] = tmp; sv_ok[3] = true; } break;
|
||||||
|
case LPP_ALTITUDE:
|
||||||
|
r.readAltitude(tmp);
|
||||||
|
if (!sv_ok[4]) { sv[4] = tmp; sv_ok[4] = true; } break;
|
||||||
|
case LPP_LUMINOSITY:
|
||||||
|
r.readLuminosity(tmp);
|
||||||
|
if (!sv_ok[5]) { sv[5] = tmp; sv_ok[5] = true; } break;
|
||||||
|
case LPP_DISTANCE:
|
||||||
|
r.readDistance(tmp);
|
||||||
|
if (!sv_ok[6]) { sv[6] = tmp; sv_ok[6] = true; } break;
|
||||||
|
case LPP_CONCENTRATION:
|
||||||
|
r.readConcentration(tmp);
|
||||||
|
if (!sv_ok[7]) { sv[7] = tmp; sv_ok[7] = true; } break;
|
||||||
|
default:
|
||||||
|
r.skipData(type); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// board battery takes precedence over INA sensor voltage
|
||||||
|
if (batt_volts >= 0.0f) { sv[3] = batt_volts; sv_ok[3] = true; }
|
||||||
|
|
||||||
int oi = 0;
|
int oi = 0;
|
||||||
const char* p = tmpl;
|
const char* p = tmpl;
|
||||||
while (*p && oi < out_len - 1) {
|
while (*p && oi < out_len - 1) {
|
||||||
|
// helper macro: append a buffer whose length is already known
|
||||||
|
#define APPEND(s, slen) do { \
|
||||||
|
int _l = (slen); \
|
||||||
|
if (oi + _l < out_len - 1) { memcpy(out + oi, (s), _l); oi += _l; } \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
if (strncmp(p, "{loc}", 5) == 0) {
|
if (strncmp(p, "{loc}", 5) == 0) {
|
||||||
char lb[32];
|
char lb[32];
|
||||||
if (gps_valid)
|
if (gps_valid) snprintf(lb, sizeof(lb), "%.5f,%.5f", lat, lon);
|
||||||
snprintf(lb, sizeof(lb), "%.5f,%.5f", lat, lon);
|
else strcpy(lb, "no GPS");
|
||||||
else
|
APPEND(lb, strlen(lb)); p += 5;
|
||||||
strcpy(lb, "no GPS");
|
|
||||||
int ll = strlen(lb);
|
|
||||||
if (oi + ll < out_len - 1) { memcpy(out + oi, lb, ll); oi += ll; }
|
|
||||||
p += 5;
|
|
||||||
} else if (strncmp(p, "{time}", 6) == 0) {
|
} else if (strncmp(p, "{time}", 6) == 0) {
|
||||||
if (utc_ts > 1000000000UL) {
|
if (utc_ts > 1000000000UL) {
|
||||||
uint32_t local_ts = utc_ts + (int32_t)tz_hours * 3600;
|
uint32_t local_ts = utc_ts + (int32_t)tz_hours * 3600;
|
||||||
@@ -30,13 +87,46 @@ inline void expandMsg(const char* tmpl, char* out, int out_len,
|
|||||||
struct tm* ti = gmtime(&t);
|
struct tm* ti = gmtime(&t);
|
||||||
char tb[8];
|
char tb[8];
|
||||||
snprintf(tb, sizeof(tb), "%02d:%02d", ti->tm_hour, ti->tm_min);
|
snprintf(tb, sizeof(tb), "%02d:%02d", ti->tm_hour, ti->tm_min);
|
||||||
int tl = strlen(tb);
|
APPEND(tb, strlen(tb));
|
||||||
if (oi + tl < out_len - 1) { memcpy(out + oi, tb, tl); oi += tl; }
|
|
||||||
}
|
}
|
||||||
p += 6;
|
p += 6;
|
||||||
|
} else if (strncmp(p, "{temp}", 6) == 0) {
|
||||||
|
if (sv_ok[0]) { char b[10]; snprintf(b,sizeof(b),"%.1fC",sv[0]); APPEND(b,strlen(b)); }
|
||||||
|
else { APPEND("{temp}", 6); }
|
||||||
|
p += 6;
|
||||||
|
} else if (strncmp(p, "{hum}", 5) == 0) {
|
||||||
|
if (sv_ok[1]) { char b[8]; snprintf(b,sizeof(b),"%.0f%%",sv[1]); APPEND(b,strlen(b)); }
|
||||||
|
else { APPEND("{hum}", 5); }
|
||||||
|
p += 5;
|
||||||
|
} else if (strncmp(p, "{pres}", 6) == 0) {
|
||||||
|
if (sv_ok[2]) { char b[12]; snprintf(b,sizeof(b),"%.0fhPa",sv[2]); APPEND(b,strlen(b)); }
|
||||||
|
else { APPEND("{pres}", 6); }
|
||||||
|
p += 6;
|
||||||
|
} else if (strncmp(p, "{batt}", 6) == 0) {
|
||||||
|
if (sv_ok[3]) { char b[8]; snprintf(b,sizeof(b),"%.2fV",sv[3]); APPEND(b,strlen(b)); }
|
||||||
|
else { APPEND("{batt}", 6); }
|
||||||
|
p += 6;
|
||||||
|
} else if (strncmp(p, "{alt}", 5) == 0) {
|
||||||
|
if (sv_ok[4]) { char b[10]; snprintf(b,sizeof(b),"%.0fm",sv[4]); APPEND(b,strlen(b)); }
|
||||||
|
else { APPEND("{alt}", 5); }
|
||||||
|
p += 5;
|
||||||
|
} else if (strncmp(p, "{lux}", 5) == 0) {
|
||||||
|
if (sv_ok[5]) { char b[10]; snprintf(b,sizeof(b),"%.0flux",sv[5]); APPEND(b,strlen(b)); }
|
||||||
|
else { APPEND("{lux}", 5); }
|
||||||
|
p += 5;
|
||||||
|
} else if (strncmp(p, "{dist}", 6) == 0) {
|
||||||
|
if (sv_ok[6]) { char b[12]; snprintf(b,sizeof(b),"%.2fm",sv[6]); APPEND(b,strlen(b)); }
|
||||||
|
else { APPEND("{dist}", 6); }
|
||||||
|
p += 6;
|
||||||
|
} else if (strncmp(p, "{co2}", 5) == 0) {
|
||||||
|
if (sv_ok[7]) { char b[12]; snprintf(b,sizeof(b),"%.0fppm",sv[7]); APPEND(b,strlen(b)); }
|
||||||
|
else { APPEND("{co2}", 5); }
|
||||||
|
p += 5;
|
||||||
} else {
|
} else {
|
||||||
out[oi++] = *p++;
|
out[oi++] = *p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef APPEND
|
||||||
}
|
}
|
||||||
out[oi] = '\0';
|
out[oi] = '\0';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ void MyMesh::tryBotReplyDM(const ContactInfo& from, const char* text) {
|
|||||||
expandMsg(_prefs.bot_reply_dm, expanded, sizeof(expanded),
|
expandMsg(_prefs.bot_reply_dm, expanded, sizeof(expanded),
|
||||||
sensors.node_lat, sensors.node_lon,
|
sensors.node_lat, sensors.node_lon,
|
||||||
sensors.node_lat != 0.0 || sensors.node_lon != 0.0,
|
sensors.node_lat != 0.0 || sensors.node_lon != 0.0,
|
||||||
ts, _prefs.tz_offset_hours);
|
ts, _prefs.tz_offset_hours,
|
||||||
|
&sensors, (float)board.getBattMilliVolts() / 1000.0f);
|
||||||
uint32_t expected_ack, est_timeout;
|
uint32_t expected_ack, est_timeout;
|
||||||
if (sendMessage(from, ts, 0, expanded, expected_ack, est_timeout) != MSG_SEND_FAILED) {
|
if (sendMessage(from, ts, 0, expanded, expected_ack, est_timeout) != MSG_SEND_FAILED) {
|
||||||
_bot_last_reply_ms = millis();
|
_bot_last_reply_ms = millis();
|
||||||
@@ -57,7 +58,8 @@ void MyMesh::tryBotReplyChannel(uint8_t channel_idx, const char* text) {
|
|||||||
expandMsg(_prefs.bot_reply_ch, expanded, sizeof(expanded),
|
expandMsg(_prefs.bot_reply_ch, expanded, sizeof(expanded),
|
||||||
sensors.node_lat, sensors.node_lon,
|
sensors.node_lat, sensors.node_lon,
|
||||||
sensors.node_lat != 0.0 || sensors.node_lon != 0.0,
|
sensors.node_lat != 0.0 || sensors.node_lon != 0.0,
|
||||||
ts, _prefs.tz_offset_hours);
|
ts, _prefs.tz_offset_hours,
|
||||||
|
&sensors, (float)board.getBattMilliVolts() / 1000.0f);
|
||||||
int rlen = strlen(expanded);
|
int rlen = strlen(expanded);
|
||||||
if (sendGroupMessage(ts, ch.channel, _prefs.node_name, expanded, rlen)) {
|
if (sendGroupMessage(ts, ch.channel, _prefs.node_name, expanded, rlen)) {
|
||||||
_bot_last_reply_ms = millis();
|
_bot_last_reply_ms = millis();
|
||||||
|
|||||||
@@ -175,6 +175,8 @@ public:
|
|||||||
max = sizeof(_prefs->bot_reply_ch) - 1;
|
max = sizeof(_prefs->bot_reply_ch) - 1;
|
||||||
}
|
}
|
||||||
_kb.begin(initial, max);
|
_kb.begin(initial, max);
|
||||||
|
if (_sel != 2) // trigger field doesn't support sensor placeholders
|
||||||
|
kbAddSensorPlaceholders(_kb, &sensors);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ static const char KB_CHARS[4][10] = {
|
|||||||
};
|
};
|
||||||
static const int KB_ROWS_CHAR = 4;
|
static const int KB_ROWS_CHAR = 4;
|
||||||
static const int KB_COLS_CHAR = 10;
|
static const int KB_COLS_CHAR = 10;
|
||||||
static const int KB_SPECIAL = 5; // [^] [Sp] [Del] [{}] [OK]
|
static const int KB_SPECIAL = 5; // [^] [Sp] [De] [{}] [OK]
|
||||||
static const char* KB_PH_LIST[] = { "{loc}", "{time}" };
|
|
||||||
static const int KB_PH_COUNT = 2;
|
|
||||||
static const int KB_MAX_LEN = 139;
|
static const int KB_MAX_LEN = 139;
|
||||||
static const int KB_CELL_W = 12; // 10 cols × 12px = 120px of 128px display
|
static const int KB_CELL_W = 12; // 10 cols × 12px = 120px of 128px display
|
||||||
static const int KB_CELL_H = 9;
|
static const int KB_CELL_H = 9;
|
||||||
@@ -23,6 +21,10 @@ static const int KB_SEP_Y = 9;
|
|||||||
static const int KB_CHARS_Y = 11;
|
static const int KB_CHARS_Y = 11;
|
||||||
static const int KB_SPECIAL_Y = 48;
|
static const int KB_SPECIAL_Y = 48;
|
||||||
|
|
||||||
|
static const int KB_PH_MAX = 12; // max placeholders in list
|
||||||
|
static const int KB_PH_LEN = 9; // max placeholder string length incl. null
|
||||||
|
static const int KB_PH_VISIBLE = 3; // items shown at once in overlay
|
||||||
|
|
||||||
struct KeyboardWidget {
|
struct KeyboardWidget {
|
||||||
char buf[KB_MAX_LEN + 1];
|
char buf[KB_MAX_LEN + 1];
|
||||||
int len;
|
int len;
|
||||||
@@ -31,6 +33,9 @@ struct KeyboardWidget {
|
|||||||
bool caps;
|
bool caps;
|
||||||
bool ph_mode;
|
bool ph_mode;
|
||||||
int ph_sel;
|
int ph_sel;
|
||||||
|
int ph_scroll;
|
||||||
|
char _ph_buf[KB_PH_MAX][KB_PH_LEN];
|
||||||
|
int _ph_count;
|
||||||
|
|
||||||
enum Result { NONE, DONE, CANCELLED };
|
enum Result { NONE, DONE, CANCELLED };
|
||||||
|
|
||||||
@@ -41,7 +46,19 @@ struct KeyboardWidget {
|
|||||||
len = strlen(buf);
|
len = strlen(buf);
|
||||||
row = col = 0;
|
row = col = 0;
|
||||||
caps = ph_mode = false;
|
caps = ph_mode = false;
|
||||||
ph_sel = 0;
|
ph_sel = ph_scroll = 0;
|
||||||
|
// default placeholders — always available
|
||||||
|
_ph_count = 0;
|
||||||
|
addPlaceholder("{loc}");
|
||||||
|
addPlaceholder("{time}");
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPlaceholder(const char* ph) {
|
||||||
|
if (_ph_count < KB_PH_MAX) {
|
||||||
|
strncpy(_ph_buf[_ph_count], ph, KB_PH_LEN - 1);
|
||||||
|
_ph_buf[_ph_count][KB_PH_LEN - 1] = '\0';
|
||||||
|
_ph_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int render(DisplayDriver& display) {
|
int render(DisplayDriver& display) {
|
||||||
@@ -99,16 +116,28 @@ struct KeyboardWidget {
|
|||||||
|
|
||||||
// placeholder picker overlay
|
// placeholder picker overlay
|
||||||
if (ph_mode) {
|
if (ph_mode) {
|
||||||
|
int box_h = 12 + KB_PH_VISIBLE * 10;
|
||||||
display.setColor(DisplayDriver::DARK);
|
display.setColor(DisplayDriver::DARK);
|
||||||
display.fillRect(20, 20, 88, 12 + KB_PH_COUNT * 10);
|
display.fillRect(20, 20, 88, box_h);
|
||||||
display.setColor(DisplayDriver::LIGHT);
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
display.drawRect(20, 20, 88, 12 + KB_PH_COUNT * 10);
|
display.drawRect(20, 20, 88, box_h);
|
||||||
display.setCursor(24, 21);
|
display.setCursor(24, 21);
|
||||||
display.print("Placeholder:");
|
display.print("Placeholder:");
|
||||||
display.fillRect(20, 30, 88, 1);
|
display.fillRect(20, 30, 88, 1);
|
||||||
for (int i = 0; i < KB_PH_COUNT; i++) {
|
|
||||||
int py = 33 + i * 10;
|
if (ph_scroll > 0) {
|
||||||
if (i == ph_sel) {
|
display.setCursor(100, 21);
|
||||||
|
display.print("^");
|
||||||
|
}
|
||||||
|
if (ph_scroll + KB_PH_VISIBLE < _ph_count) {
|
||||||
|
display.setCursor(100, 33 + (KB_PH_VISIBLE - 1) * 10);
|
||||||
|
display.print("v");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < KB_PH_VISIBLE && (ph_scroll + i) < _ph_count; i++) {
|
||||||
|
int idx = ph_scroll + i;
|
||||||
|
int py = 33 + i * 10;
|
||||||
|
if (idx == ph_sel) {
|
||||||
display.setColor(DisplayDriver::LIGHT);
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
display.fillRect(21, py - 1, 86, 10);
|
display.fillRect(21, py - 1, 86, 10);
|
||||||
display.setColor(DisplayDriver::DARK);
|
display.setColor(DisplayDriver::DARK);
|
||||||
@@ -116,7 +145,7 @@ struct KeyboardWidget {
|
|||||||
display.setColor(DisplayDriver::LIGHT);
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
}
|
}
|
||||||
display.setCursor(24, py);
|
display.setCursor(24, py);
|
||||||
display.print(KB_PH_LIST[i]);
|
display.print(_ph_buf[idx]);
|
||||||
}
|
}
|
||||||
display.setColor(DisplayDriver::LIGHT);
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
}
|
}
|
||||||
@@ -127,10 +156,18 @@ struct KeyboardWidget {
|
|||||||
Result handleInput(char c) {
|
Result handleInput(char c) {
|
||||||
// placeholder overlay consumes all input
|
// placeholder overlay consumes all input
|
||||||
if (ph_mode) {
|
if (ph_mode) {
|
||||||
if (c == KEY_UP && ph_sel > 0) { ph_sel--; return NONE; }
|
if (c == KEY_UP && ph_sel > 0) {
|
||||||
if (c == KEY_DOWN && ph_sel < KB_PH_COUNT - 1){ ph_sel++; return NONE; }
|
ph_sel--;
|
||||||
|
if (ph_sel < ph_scroll) ph_scroll = ph_sel;
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
if (c == KEY_DOWN && ph_sel < _ph_count - 1) {
|
||||||
|
ph_sel++;
|
||||||
|
if (ph_sel >= ph_scroll + KB_PH_VISIBLE) ph_scroll = ph_sel - KB_PH_VISIBLE + 1;
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
if (c == KEY_ENTER) {
|
if (c == KEY_ENTER) {
|
||||||
const char* ph = KB_PH_LIST[ph_sel];
|
const char* ph = _ph_buf[ph_sel];
|
||||||
int ph_len = strlen(ph);
|
int ph_len = strlen(ph);
|
||||||
if (len + ph_len <= max_len) {
|
if (len + ph_len <= max_len) {
|
||||||
memcpy(buf + len, ph, ph_len);
|
memcpy(buf + len, ph, ph_len);
|
||||||
@@ -189,8 +226,9 @@ struct KeyboardWidget {
|
|||||||
if (len > 0) buf[--len] = '\0';
|
if (len > 0) buf[--len] = '\0';
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
ph_mode = true;
|
ph_mode = true;
|
||||||
ph_sel = 0;
|
ph_sel = 0;
|
||||||
|
ph_scroll = 0;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
return DONE;
|
return DONE;
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
// Populates a KeyboardWidget's placeholder list with sensor types currently
|
||||||
|
// detected by SensorManager. Always adds {loc} and {time} via begin(); this
|
||||||
|
// helper appends the sensor-specific entries on top.
|
||||||
|
|
||||||
|
#include "KeyboardWidget.h"
|
||||||
|
#include <helpers/SensorManager.h>
|
||||||
|
#include <helpers/sensors/LPPDataHelpers.h>
|
||||||
|
|
||||||
|
inline void kbAddSensorPlaceholders(KeyboardWidget& kb, SensorManager* sm) {
|
||||||
|
if (!sm) return;
|
||||||
|
uint8_t types[16];
|
||||||
|
int tc = sm->getAvailableLPPTypes(types, 16);
|
||||||
|
|
||||||
|
static const struct { uint8_t t; const char* ph; } MAP[] = {
|
||||||
|
{ LPP_TEMPERATURE, "{temp}" },
|
||||||
|
{ LPP_RELATIVE_HUMIDITY, "{hum}" },
|
||||||
|
{ LPP_BAROMETRIC_PRESSURE, "{pres}" },
|
||||||
|
{ LPP_VOLTAGE, "{batt}" },
|
||||||
|
{ LPP_ALTITUDE, "{alt}" },
|
||||||
|
{ LPP_LUMINOSITY, "{lux}" },
|
||||||
|
{ LPP_DISTANCE, "{dist}" },
|
||||||
|
{ LPP_CONCENTRATION, "{co2}" },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& m : MAP) {
|
||||||
|
for (int i = 0; i < tc; i++) {
|
||||||
|
if (types[i] == m.t) { kb.addPlaceholder(m.ph); break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -99,6 +99,7 @@ static const uint16_t HP_ALL = 0x01FF;
|
|||||||
|
|
||||||
#include "KeyboardWidget.h"
|
#include "KeyboardWidget.h"
|
||||||
#include "FullscreenMsgView.h"
|
#include "FullscreenMsgView.h"
|
||||||
|
#include "SensorPlaceholders.h"
|
||||||
|
|
||||||
class SettingsScreen : public UIScreen {
|
class SettingsScreen : public UIScreen {
|
||||||
UITask* _task;
|
UITask* _task;
|
||||||
@@ -575,6 +576,7 @@ public:
|
|||||||
int slot = msgSlotIndex(_selected);
|
int slot = msgSlotIndex(_selected);
|
||||||
_edit_slot = slot;
|
_edit_slot = slot;
|
||||||
_kb.begin(p ? p->custom_msgs[slot] : "");
|
_kb.begin(p ? p->custom_msgs[slot] : "");
|
||||||
|
kbAddSensorPlaceholders(_kb, &sensors);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -667,9 +669,11 @@ class QuickMsgScreen : public UIScreen {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
NodePrefs* np = _task->getNodePrefs();
|
NodePrefs* np = _task->getNodePrefs();
|
||||||
|
float batt = (float)board.getBattMilliVolts() / 1000.0f;
|
||||||
::expandMsg(tmpl, out, out_len, lat, lon, gps_valid,
|
::expandMsg(tmpl, out, out_len, lat, lon, gps_valid,
|
||||||
rtc_clock.getCurrentTime(),
|
rtc_clock.getCurrentTime(),
|
||||||
np ? np->tz_offset_hours : 0);
|
np ? np->tz_offset_hours : 0,
|
||||||
|
&sensors, batt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupMsgPick() {
|
void setupMsgPick() {
|
||||||
@@ -1624,6 +1628,7 @@ public:
|
|||||||
if (c == KEY_ENTER) {
|
if (c == KEY_ENTER) {
|
||||||
if (_msg_sel == 0) {
|
if (_msg_sel == 0) {
|
||||||
_kb.begin();
|
_kb.begin();
|
||||||
|
kbAddSensorPlaceholders(_kb, &sensors);
|
||||||
_phase = KEYBOARD;
|
_phase = KEYBOARD;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user