Skip to content

Commit 1257c6b

Browse files
authored
Merge pull request #739 from fdlamotte/ui_sensors_page
ui: sensors page
2 parents f35e259 + d83cdc5 commit 1257c6b

File tree

4 files changed

+338
-1
lines changed

4 files changed

+338
-1
lines changed

examples/companion_radio/ui-new/UITask.cpp

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class HomeScreen : public UIScreen {
7575
RADIO,
7676
BLUETOOTH,
7777
ADVERT,
78+
#if UI_SENSORS_PAGE == 1
79+
SENSORS,
80+
#endif
7881
SHUTDOWN,
7982
Count // keep as last
8083
};
@@ -113,9 +116,37 @@ class HomeScreen : public UIScreen {
113116
display.fillRect(iconX + 2, iconY + 2, fillWidth, iconHeight - 4);
114117
}
115118

119+
CayenneLPP sensors_lpp;
120+
int sensors_nb = 0;
121+
bool sensors_scroll = false;
122+
int sensors_scroll_offset = 0;
123+
int next_sensors_refresh = 0;
124+
125+
void refresh_sensors() {
126+
if (millis() > next_sensors_refresh) {
127+
sensors_lpp.reset();
128+
sensors_nb = 0;
129+
sensors_lpp.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
130+
sensors.querySensors(0xFF, sensors_lpp);
131+
LPPReader reader (sensors_lpp.getBuffer(), sensors_lpp.getSize());
132+
uint8_t channel, type;
133+
while(reader.readHeader(channel, type)) {
134+
reader.skipData(type);
135+
sensors_nb ++;
136+
}
137+
sensors_scroll = sensors_nb > UI_RECENT_LIST_SIZE;
138+
#if AUTO_OFF_MILLIS > 0
139+
next_sensors_refresh = millis() + 5000; // refresh sensor values every 5 sec
140+
#else
141+
next_sensors_refresh = millis() + 60000; // refresh sensor values every 1 min
142+
#endif
143+
}
144+
}
145+
116146
public:
117147
HomeScreen(UITask* task, mesh::RTCClock* rtc, SensorManager* sensors, NodePrefs* node_prefs)
118-
: _task(task), _rtc(rtc), _sensors(sensors), _node_prefs(node_prefs), _page(0), _shutdown_init(false) { }
148+
: _task(task), _rtc(rtc), _sensors(sensors), _node_prefs(node_prefs), _page(0),
149+
_shutdown_init(false), sensors_lpp(200) { }
119150

120151
void poll() override {
121152
if (_shutdown_init && !_task->isButtonPressed()) { // must wait for USR button to be released
@@ -211,6 +242,78 @@ class HomeScreen : public UIScreen {
211242
display.setColor(DisplayDriver::GREEN);
212243
display.drawXbm((display.width() - 32) / 2, 18, advert_icon, 32, 32);
213244
display.drawTextCentered(display.width() / 2, 64 - 11, "advert: " PRESS_LABEL);
245+
#if UI_SENSORS_PAGE == 1
246+
} else if (_page == HomePage::SENSORS) {
247+
int y = 18;
248+
refresh_sensors();
249+
char buf[30];
250+
char name[30];
251+
LPPReader r(sensors_lpp.getBuffer(), sensors_lpp.getSize());
252+
253+
for (int i = 0; i < sensors_scroll_offset; i++) {
254+
uint8_t channel, type;
255+
r.readHeader(channel, type);
256+
r.skipData(type);
257+
}
258+
259+
for (int i = 0; i < (sensors_scroll?UI_RECENT_LIST_SIZE:sensors_nb); i++) {
260+
uint8_t channel, type;
261+
if (!r.readHeader(channel, type)) { // reached end, reset
262+
r.reset();
263+
r.readHeader(channel, type);
264+
}
265+
266+
display.setCursor(0, y);
267+
float v;
268+
switch (type) {
269+
case LPP_GPS: // GPS
270+
float lat, lon, alt;
271+
r.readGPS(lat, lon, alt);
272+
strcpy(name, "gps"); sprintf(buf, "%.4f %.4f", lat, lon);
273+
break;
274+
case LPP_VOLTAGE:
275+
r.readVoltage(v);
276+
strcpy(name, "voltage"); sprintf(buf, "%6.2f", v);
277+
break;
278+
case LPP_CURRENT:
279+
r.readCurrent(v);
280+
strcpy(name, "current"); sprintf(buf, "%.3f", v);
281+
break;
282+
case LPP_TEMPERATURE:
283+
r.readTemperature(v);
284+
strcpy(name, "temperature"); sprintf(buf, "%.2f", v);
285+
break;
286+
case LPP_RELATIVE_HUMIDITY:
287+
r.readRelativeHumidity(v);
288+
strcpy(name, "humidity"); sprintf(buf, "%.2f", v);
289+
break;
290+
case LPP_BAROMETRIC_PRESSURE:
291+
r.readPressure(v);
292+
strcpy(name, "pressure"); sprintf(buf, "%.2f", v);
293+
break;
294+
case LPP_ALTITUDE:
295+
r.readAltitude(v);
296+
strcpy(name, "altitude"); sprintf(buf, "%.0f", v);
297+
break;
298+
case LPP_POWER:
299+
r.readPower(v);
300+
strcpy(name, "power"); sprintf(buf, "%6.2f", v);
301+
break;
302+
default:
303+
r.skipData(type);
304+
strcpy(name, "unk"); sprintf(buf, "");
305+
}
306+
display.setCursor(0, y);
307+
display.print(name);
308+
display.setCursor(
309+
display.width()-display.getTextWidth(buf)-1, y
310+
);
311+
display.print(buf);
312+
y = y + 12;
313+
}
314+
if (sensors_scroll) sensors_scroll_offset = (sensors_scroll_offset+1)%sensors_nb;
315+
else sensors_scroll_offset = 0;
316+
#endif
214317
} else if (_page == HomePage::SHUTDOWN) {
215318
display.setColor(DisplayDriver::GREEN);
216319
display.setTextSize(1);
@@ -255,6 +358,13 @@ class HomeScreen : public UIScreen {
255358
}
256359
return true;
257360
}
361+
#if UI_SENSORS_PAGE == 1
362+
if (c == KEY_ENTER && _page == HomePage::SENSORS) {
363+
_task->toggleGPS();
364+
next_sensors_refresh=0;
365+
return true;
366+
}
367+
#endif
258368
if (c == KEY_ENTER && _page == HomePage::SHUTDOWN) {
259369
_shutdown_init = true; // need to wait for button to be released
260370
return true;

examples/companion_radio/ui-new/UITask.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <helpers/SensorManager.h>
77
#include <helpers/BaseSerialInterface.h>
88
#include <Arduino.h>
9+
#include <helpers/sensors/LPPDataHelpers.h>
910

1011
#ifdef PIN_BUZZER
1112
#include <helpers/ui/buzzer.h>
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
5+
#define LPP_DIGITAL_INPUT 0 // 1 byte
6+
#define LPP_DIGITAL_OUTPUT 1 // 1 byte
7+
#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed
8+
#define LPP_ANALOG_OUTPUT 3 // 2 bytes, 0.01 signed
9+
#define LPP_GENERIC_SENSOR 100 // 4 bytes, unsigned
10+
#define LPP_LUMINOSITY 101 // 2 bytes, 1 lux unsigned
11+
#define LPP_PRESENCE 102 // 1 byte, bool
12+
#define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed
13+
#define LPP_RELATIVE_HUMIDITY 104 // 1 byte, 0.5% unsigned
14+
#define LPP_ACCELEROMETER 113 // 2 bytes per axis, 0.001G
15+
#define LPP_BAROMETRIC_PRESSURE 115 // 2 bytes 0.1hPa unsigned
16+
#define LPP_VOLTAGE 116 // 2 bytes 0.01V unsigned
17+
#define LPP_CURRENT 117 // 2 bytes 0.001A unsigned
18+
#define LPP_FREQUENCY 118 // 4 bytes 1Hz unsigned
19+
#define LPP_PERCENTAGE 120 // 1 byte 1-100% unsigned
20+
#define LPP_ALTITUDE 121 // 2 byte 1m signed
21+
#define LPP_CONCENTRATION 125 // 2 bytes, 1 ppm unsigned
22+
#define LPP_POWER 128 // 2 byte, 1W, unsigned
23+
#define LPP_DISTANCE 130 // 4 byte, 0.001m, unsigned
24+
#define LPP_ENERGY 131 // 4 byte, 0.001kWh, unsigned
25+
#define LPP_DIRECTION 132 // 2 bytes, 1deg, unsigned
26+
#define LPP_UNIXTIME 133 // 4 bytes, unsigned
27+
#define LPP_GYROMETER 134 // 2 bytes per axis, 0.01 °/s
28+
#define LPP_COLOUR 135 // 1 byte per RGB Color
29+
#define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter
30+
#define LPP_SWITCH 142 // 1 byte, 0/1
31+
#define LPP_POLYLINE 240 // 1 byte size, 1 byte delta factor, 3 byte lon/lat 0.0001° * factor, n (size-8) bytes deltas
32+
33+
// Multipliers
34+
#define LPP_DIGITAL_INPUT_MULT 1
35+
#define LPP_DIGITAL_OUTPUT_MULT 1
36+
#define LPP_ANALOG_INPUT_MULT 100
37+
#define LPP_ANALOG_OUTPUT_MULT 100
38+
#define LPP_GENERIC_SENSOR_MULT 1
39+
#define LPP_LUMINOSITY_MULT 1
40+
#define LPP_PRESENCE_MULT 1
41+
#define LPP_TEMPERATURE_MULT 10
42+
#define LPP_RELATIVE_HUMIDITY_MULT 2
43+
#define LPP_ACCELEROMETER_MULT 1000
44+
#define LPP_BAROMETRIC_PRESSURE_MULT 10
45+
#define LPP_VOLTAGE_MULT 100
46+
#define LPP_CURRENT_MULT 1000
47+
#define LPP_FREQUENCY_MULT 1
48+
#define LPP_PERCENTAGE_MULT 1
49+
#define LPP_ALTITUDE_MULT 1
50+
#define LPP_POWER_MULT 1
51+
#define LPP_DISTANCE_MULT 1000
52+
#define LPP_ENERGY_MULT 1000
53+
#define LPP_DIRECTION_MULT 1
54+
#define LPP_UNIXTIME_MULT 1
55+
#define LPP_GYROMETER_MULT 100
56+
#define LPP_GPS_LAT_LON_MULT 10000
57+
#define LPP_GPS_ALT_MULT 100
58+
#define LPP_SWITCH_MULT 1
59+
#define LPP_CONCENTRATION_MULT 1
60+
#define LPP_COLOUR_MULT 1
61+
62+
#define LPP_ERROR_OK 0
63+
#define LPP_ERROR_OVERFLOW 1
64+
#define LPP_ERROR_UNKOWN_TYPE 2
65+
66+
class LPPReader {
67+
const uint8_t* _buf;
68+
uint8_t _len;
69+
uint8_t _pos;
70+
71+
float getFloat(const uint8_t * buffer, uint8_t size, uint32_t multiplier, bool is_signed) {
72+
uint32_t value = 0;
73+
for (uint8_t i = 0; i < size; i++) {
74+
value = (value << 8) + buffer[i];
75+
}
76+
77+
int sign = 1;
78+
if (is_signed) {
79+
uint32_t bit = 1ul << ((size * 8) - 1);
80+
if ((value & bit) == bit) {
81+
value = (bit << 1) - value;
82+
sign = -1;
83+
}
84+
}
85+
return sign * ((float) value / multiplier);
86+
}
87+
88+
public:
89+
LPPReader(const uint8_t buf[], uint8_t len) : _buf(buf), _len(len), _pos(0) { }
90+
91+
void reset() {
92+
_pos = 0;
93+
}
94+
95+
bool readHeader(uint8_t& channel, uint8_t& type) {
96+
if (_pos + 2 < _len) {
97+
channel = _buf[_pos++];
98+
type = _buf[_pos++];
99+
100+
return channel != 0; // channel 0 is End-of-data
101+
}
102+
return false; // end-of-buffer
103+
}
104+
105+
bool readGPS(float& lat, float& lon, float& alt) {
106+
lat = getFloat(&_buf[_pos], 3, 10000, true); _pos += 3;
107+
lon = getFloat(&_buf[_pos], 3, 10000, true); _pos += 3;
108+
alt = getFloat(&_buf[_pos], 3, 100, true); _pos += 3;
109+
return _pos <= _len;
110+
}
111+
bool readVoltage(float& voltage) {
112+
voltage = getFloat(&_buf[_pos], 2, 100, false); _pos += 2;
113+
return _pos <= _len;
114+
}
115+
bool readCurrent(float& amps) {
116+
amps = getFloat(&_buf[_pos], 2, 1000, false); _pos += 2;
117+
return _pos <= _len;
118+
}
119+
bool readPower(float& watts) {
120+
watts = getFloat(&_buf[_pos], 2, 1, false); _pos += 2;
121+
return _pos <= _len;
122+
}
123+
bool readTemperature(float& degrees_c) {
124+
degrees_c = getFloat(&_buf[_pos], 2, 10, true); _pos += 2;
125+
return _pos <= _len;
126+
}
127+
bool readPressure(float& pa) {
128+
pa = getFloat(&_buf[_pos], 2, 10, false); _pos += 2;
129+
return _pos <= _len;
130+
}
131+
bool readRelativeHumidity(float& pct) {
132+
pct = getFloat(&_buf[_pos], 1, 2, false); _pos += 1;
133+
return _pos <= _len;
134+
}
135+
bool readAltitude(float& m) {
136+
m = getFloat(&_buf[_pos], 2, 1, true); _pos += 2;
137+
return _pos <= _len;
138+
}
139+
140+
void skipData(uint8_t type) {
141+
switch (type) {
142+
case LPP_GPS:
143+
_pos += 9; break;
144+
case LPP_POLYLINE:
145+
_pos += 8; break; // TODO: this is MINIMIUM
146+
case LPP_GYROMETER:
147+
case LPP_ACCELEROMETER:
148+
_pos += 6; break;
149+
case LPP_GENERIC_SENSOR:
150+
case LPP_FREQUENCY:
151+
case LPP_DISTANCE:
152+
case LPP_ENERGY:
153+
case LPP_UNIXTIME:
154+
_pos += 4; break;
155+
case LPP_COLOUR:
156+
_pos += 3; break;
157+
case LPP_ANALOG_INPUT:
158+
case LPP_ANALOG_OUTPUT:
159+
case LPP_LUMINOSITY:
160+
case LPP_TEMPERATURE:
161+
case LPP_CONCENTRATION:
162+
case LPP_BAROMETRIC_PRESSURE:
163+
case LPP_ALTITUDE:
164+
case LPP_VOLTAGE:
165+
case LPP_CURRENT:
166+
case LPP_DIRECTION:
167+
case LPP_POWER:
168+
_pos += 2; break;
169+
default:
170+
_pos++;
171+
}
172+
}
173+
};
174+
175+
class LPPWriter {
176+
uint8_t* _buf;
177+
uint8_t _max_len;
178+
uint8_t _len;
179+
180+
void write(uint16_t value) {
181+
_buf[_len++] = (value >> 8) & 0xFF; // MSB
182+
_buf[_len++] = value & 0xFF; // LSB
183+
}
184+
185+
public:
186+
LPPWriter(uint8_t buf[], uint8_t max_len): _buf(buf), _max_len(max_len), _len(0) { }
187+
188+
bool writeVoltage(uint8_t channel, float voltage) {
189+
if (_len + 4 <= _max_len) {
190+
_buf[_len++] = channel;
191+
_buf[_len++] = LPP_VOLTAGE;
192+
uint16_t value = voltage * 100;
193+
write(value);
194+
return true;
195+
}
196+
return false;
197+
}
198+
199+
bool writeGPS(uint8_t channel, float lat, float lon, float alt) {
200+
if (_len + 11 <= _max_len) {
201+
_buf[_len++] = channel;
202+
_buf[_len++] = LPP_GPS;
203+
204+
int32_t lati = lat * 10000; // we lose some precision :-(
205+
int32_t loni = lon * 10000;
206+
int32_t alti = alt * 100;
207+
208+
_buf[_len++] = lati >> 16;
209+
_buf[_len++] = lati >> 8;
210+
_buf[_len++] = lati;
211+
_buf[_len++] = loni >> 16;
212+
_buf[_len++] = loni >> 8;
213+
_buf[_len++] = loni;
214+
_buf[_len++] = alti >> 16;
215+
_buf[_len++] = alti >> 8;
216+
_buf[_len++] = alti;
217+
return true;
218+
}
219+
return false;
220+
}
221+
222+
uint8_t length() { return _len; }
223+
};

variants/lilygo_techo/platformio.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ build_flags =
8888
-D BLE_PIN_CODE=123456
8989
; -D BLE_DEBUG_LOGGING=1
9090
-D OFFLINE_QUEUE_SIZE=256
91+
-D UI_RECENT_LIST_SIZE=9
92+
-D UI_SENSORS_PAGE=1
9193
; -D MESH_PACKET_LOGGING=1
9294
; -D MESH_DEBUG=1
9395
-D AUTO_SHUTDOWN_MILLIVOLTS=3300
@@ -109,6 +111,7 @@ build_flags =
109111
-D MAX_GROUP_CHANNELS=40
110112
-D OFFLINE_QUEUE_SIZE=256
111113
-D UI_RECENT_LIST_SIZE=9
114+
-D UI_SENSORS_PAGE=1
112115
-D AUTO_SHUTDOWN_MILLIVOLTS=3300
113116
build_src_filter = ${LilyGo_T-Echo.build_src_filter}
114117
+<../examples/companion_radio/*.cpp>

0 commit comments

Comments
 (0)