[SSD1306] BLE devices display - Take 2 (#1492)
* BLE Display - THB, THBX, PLANT, AIR, BATT, BODY * SCALE * BBQ * Filter MS-CDP, GAEN and IBEACON * Mopeka & Smart Dry * ACEL ACEL sensor, as most also have temp and hum, but no acceleration info display included so far. * Only display when properties are present Only display when properties are present, to avoid model only display for devices which require active scanning at a larger interval, e.g. Mi Band and similar. * LilyGo-BLE environment * BLE display relocated BLE display relocated to have pubadvdata "type" in message, required for the different type display functions.
This commit is contained in:
1 parent
a6e0f6094c
commit
c77a16867d
5 files changed
+362
-51
No files matched your search
@@ -39,7 +39,9 @@ jobs:
|
||||
- "esp32dev-rtl_433"
|
||||
- "esp32doitv1-aithinker-r01-sx1278"
|
||||
- "heltec-rtl_433"
|
||||
- "heltec-ble"
|
||||
- "lilygo-rtl_433"
|
||||
- "lilygo-ble"
|
||||
- "esp32dev-multi_receiver"
|
||||
- "tinypico-ble"
|
||||
- "ttgo-lora32-v1-868"
|
||||
|
||||
+53
-1
@@ -744,9 +744,34 @@ build_flags =
|
||||
; '-DJSON_TO_LCD=true'
|
||||
; '-DLOG_LEVEL_LCD=LOG_LEVEL_NOTICE'
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = Gateway using RTL_433_ESP and RadioLib
|
||||
|
||||
[env:heltec-ble]
|
||||
platform = ${com.esp32_platform}
|
||||
board = heltec_wifi_lora_32_V2
|
||||
; ~/.platformio/packages/framework-arduinoespressif32/variants/.../pins_arduino.h
|
||||
board_build.partitions = min_spiffs.csv
|
||||
lib_deps =
|
||||
${com-esp.lib_deps}
|
||||
${libraries.wifimanager32}
|
||||
${libraries.ssd1306}
|
||||
${libraries.ble}
|
||||
${libraries.decoder}
|
||||
build_flags =
|
||||
${com-esp.build_flags}
|
||||
; *** OpenMQTTGateway Config ***
|
||||
;'-UZmqttDiscovery' ; disables MQTT Discovery
|
||||
'-DZgatewayBT="BT"'
|
||||
'-DGateway_Name="OpenMQTTGateway_heltec_ble"'
|
||||
; *** ssd1306 Display Options ***
|
||||
'-DZdisplaySSD1306="HELTEC_SSD1306"'
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = Heltec BLE gateway with adaptive scanning activated, automatically adapts the scan parameters depending on your devices
|
||||
|
||||
[env:lilygo-rtl_433]
|
||||
platform = ${com.esp32_platform}
|
||||
board = ttgo-lora32-v21
|
||||
@@ -772,11 +797,36 @@ build_flags =
|
||||
; '-DJSON_TO_LCD=true'
|
||||
; '-DLOG_LEVEL_LCD=LOG_LEVEL_NOTICE'
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=100'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = For ESP32, Gateway using RTL_433_ESP and RadioLib
|
||||
custom_hardware = ESP32 LILYGO LoRa32 V2.1
|
||||
|
||||
[env:lilygo-ble]
|
||||
platform = ${com.esp32_platform}
|
||||
board = ttgo-lora32-v21
|
||||
; ~/.platformio/packages/framework-arduinoespressif32/variants/.../pins_arduino.h
|
||||
board_build.partitions = min_spiffs.csv
|
||||
lib_deps =
|
||||
${com-esp.lib_deps}
|
||||
${libraries.wifimanager32}
|
||||
${libraries.ssd1306}
|
||||
${libraries.ble}
|
||||
${libraries.decoder}
|
||||
build_flags =
|
||||
${com-esp.build_flags}
|
||||
; *** OpenMQTTGateway Config ***
|
||||
;'-UZmqttDiscovery' ; disables MQTT Discovery
|
||||
'-DZgatewayBT="BT"'
|
||||
'-DGateway_Name="OpenMQTTGateway_lilygo_ble"'
|
||||
; *** ssd1306 Display Options ***
|
||||
'-DZdisplaySSD1306="LilyGo_SSD1306"'
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = LilyGo BLE gateway with adaptive scanning activated, automatically adapts the scan parameters depending on your devices
|
||||
custom_hardware = ESP32 LILYGO LoRa32 V2.1
|
||||
|
||||
[env:esp32dev-multi_receiver]
|
||||
platform = ${com.esp32_platform}
|
||||
board = esp32dev
|
||||
@@ -914,6 +964,7 @@ build_flags =
|
||||
; '-DJSON_TO_LCD=true'
|
||||
; '-DLOG_LEVEL_LCD=LOG_LEVEL_NOTICE'
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = LORA communication 868Mhz using arduino-LoRA
|
||||
custom_hardware = ESP32 HELTEC LORA32
|
||||
@@ -941,6 +992,7 @@ build_flags =
|
||||
; '-DJSON_TO_LCD=true'
|
||||
; '-DLOG_LEVEL_LCD=LOG_LEVEL_NOTICE'
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = LORA communication 915Mhz using arduino-LoRA
|
||||
custom_hardware = ESP32 HELTEC LORA32
|
||||
|
||||
+301
-47
@@ -373,63 +373,317 @@ void ssd1306PubPrint(const char* topicori, JsonObject& data) {
|
||||
# endif
|
||||
# ifdef ZgatewayBT
|
||||
case hash("BTtoMQTT"): {
|
||||
// {"id":"49:22:07:07:1C:F6","mac_type":0,"name":"sps","rssi":-87,"brand":"Inkbird","model":"TH Sensor","model_id":"IBS-TH1","cidc":false,"tempc":0.8,"tempf":33.44,"hum":29.61,"batt":100}
|
||||
// {"id":"AA:BB:CC:DD:EE:FF","mac_type":0,"adv_type":0,"name":"sps","manufacturerdata":"de071f1000b1612908","rssi":-70,"brand":"Inkbird","model":"T(H) Sensor","model_id":"IBS-TH1/TH2/P01B","type":"THBX","cidc":false,"acts":true,"tempc":20.14,"tempf":68.252,"hum":41.27,"batt":41}
|
||||
|
||||
// Line 1
|
||||
if (data["model_id"] != "MS-CDP" && data["model_id"] != "GAEN" && data["model_id"] != "IBEACON") {
|
||||
// Line 2, 3, 4
|
||||
String line2 = "";
|
||||
String line3 = "";
|
||||
String line4 = "";
|
||||
|
||||
strlcpy(message->line1, data["brand"], OLED_TEXT_WIDTH);
|
||||
// Properties
|
||||
String properties[6] = {"", "", "", "", "", ""};
|
||||
int property = -1;
|
||||
|
||||
// Line 2
|
||||
if (data["type"] == "THB" || data["type"] == "THBX" || data["type"] == "PLANT" || data["type"] == "AIR" || data["type"] == "BATT" || data["type"] == "ACEL" || (data["type"] == "UNIQ" && data["model_id"] == "SDLS")) {
|
||||
if (data.containsKey("tempc")) {
|
||||
property++;
|
||||
char temp[5];
|
||||
if (displayMetric) {
|
||||
float temperature = data["tempc"];
|
||||
dtostrf(temperature, 3, 1, temp);
|
||||
properties[property] = "temp: " + (String)temp + "°C ";
|
||||
} else {
|
||||
float temperature = data["tempf"];
|
||||
dtostrf(temperature, 3, 1, temp);
|
||||
properties[property] = "temp: " + (String)temp + "°F ";
|
||||
}
|
||||
}
|
||||
|
||||
strlcpy(message->line2, data["model_id"], OLED_TEXT_WIDTH);
|
||||
if (data.containsKey("tempc2_dp")) {
|
||||
property++;
|
||||
char tempdp[5];
|
||||
if (displayMetric) {
|
||||
float temperature = data["tempc2_dp"];
|
||||
dtostrf(temperature, 3, 1, tempdp);
|
||||
properties[property] = "dewp: " + (String)tempdp + "°C ";
|
||||
} else {
|
||||
float temperature = data["tempf2_dp"];
|
||||
dtostrf(temperature, 3, 1, tempdp);
|
||||
properties[property] = "dewp: " + (String)tempdp + "°F ";
|
||||
}
|
||||
}
|
||||
|
||||
// Line 3
|
||||
if (data.containsKey("extprobe")) {
|
||||
property++;
|
||||
properties[property] = " ext. probe";
|
||||
}
|
||||
|
||||
String line3 = "";
|
||||
if (data.containsKey("hum")) {
|
||||
property++;
|
||||
float humidity = data["hum"];
|
||||
char hum[5];
|
||||
|
||||
if (data.containsKey("tempc")) {
|
||||
float temperature_C = data["tempc"];
|
||||
char temp[5];
|
||||
dtostrf(humidity, 3, 1, hum);
|
||||
properties[property] = "hum: " + (String)hum + "% ";
|
||||
}
|
||||
|
||||
if (displayMetric) {
|
||||
dtostrf(temperature_C, 3, 1, temp);
|
||||
line3 = "temp: " + (String)temp + "°C ";
|
||||
} else {
|
||||
dtostrf(convertTemp_CtoF(temperature_C), 3, 1, temp);
|
||||
line3 = "temp: " + (String)temp + "°F ";
|
||||
if (data.containsKey("pm25")) {
|
||||
property++;
|
||||
int pm25int = data["pm25"];
|
||||
char pm25[3];
|
||||
itoa(pm25int, pm25, 10);
|
||||
if ((data.containsKey("pm10"))) {
|
||||
properties[property] = "PM 2.5: " + (String)pm25 + " ";
|
||||
|
||||
} else {
|
||||
properties[property] = "pm2.5: " + (String)pm25 + "μg/m³ ";
|
||||
}
|
||||
}
|
||||
|
||||
if (data.containsKey("pm10")) {
|
||||
property++;
|
||||
int pm10int = data["pm10"];
|
||||
char pm10[3];
|
||||
itoa(pm10int, pm10, 10);
|
||||
if ((data.containsKey("pm25"))) {
|
||||
properties[property] = "/ 10: " + (String)pm10 + "μg/m³ ";
|
||||
|
||||
} else {
|
||||
properties[property] = "pm10: " + (String)pm10 + "μg/m³ ";
|
||||
}
|
||||
}
|
||||
|
||||
if (data.containsKey("for")) {
|
||||
property++;
|
||||
int formint = data["for"];
|
||||
char form[3];
|
||||
itoa(formint, form, 10);
|
||||
properties[property] = "CH₂O: " + (String)form + "mg/m³ ";
|
||||
}
|
||||
|
||||
if (data.containsKey("co2")) {
|
||||
property++;
|
||||
int co2int = data["co2"];
|
||||
char co2[4];
|
||||
itoa(co2int, co2, 10);
|
||||
properties[property] = "co2: " + (String)co2 + "ppm ";
|
||||
}
|
||||
|
||||
if (data.containsKey("moi")) {
|
||||
property++;
|
||||
int moiint = data["moi"];
|
||||
char moi[4];
|
||||
itoa(moiint, moi, 10);
|
||||
properties[property] = "moi: " + (String)moi + "% ";
|
||||
}
|
||||
|
||||
if (data.containsKey("lux")) {
|
||||
property++;
|
||||
int luxint = data["lux"];
|
||||
char lux[5];
|
||||
itoa(luxint, lux, 10);
|
||||
properties[property] = "lux: " + (String)lux + "lx ";
|
||||
}
|
||||
|
||||
if (data.containsKey("fer")) {
|
||||
property++;
|
||||
int ferint = data["fer"];
|
||||
char fer[7];
|
||||
itoa(ferint, fer, 10);
|
||||
properties[property] = "fer: " + (String)fer + "µS/cm ";
|
||||
}
|
||||
|
||||
if (data.containsKey("pres")) {
|
||||
property++;
|
||||
int presint = data["pres"];
|
||||
char pres[4];
|
||||
itoa(presint, pres, 10);
|
||||
properties[property] = "pres: " + (String)pres + "hPa ";
|
||||
}
|
||||
|
||||
if (data.containsKey("batt")) {
|
||||
property++;
|
||||
int battery = data["batt"];
|
||||
char batt[5];
|
||||
itoa(battery, batt, 10);
|
||||
properties[property] = "batt: " + (String)batt + "% ";
|
||||
}
|
||||
|
||||
if (data.containsKey("shake")) {
|
||||
property++;
|
||||
int shakeint = data["shake"];
|
||||
char shake[3];
|
||||
itoa(shakeint, shake, 10);
|
||||
properties[property] = "shake: " + (String)shake + " ";
|
||||
}
|
||||
|
||||
if (data.containsKey("volt")) {
|
||||
property++;
|
||||
float voltf = data["volt"];
|
||||
char volt[5];
|
||||
dtostrf(voltf, 3, 1, volt);
|
||||
properties[property] = "volt: " + (String)volt + "V ";
|
||||
}
|
||||
|
||||
if (data.containsKey("wake")) {
|
||||
property++;
|
||||
String wakestr = data["wake"];
|
||||
properties[property] = "wake: " + wakestr + " ";
|
||||
}
|
||||
|
||||
} else if (data["type"] == "BBQ") {
|
||||
String tempcstr = "";
|
||||
int j = 7;
|
||||
if (data["model_id"] == "IBT-2X(S)") {
|
||||
j = 3;
|
||||
} else if (data["model_id"] == "IBT-4X(S/C)") {
|
||||
j = 5;
|
||||
}
|
||||
|
||||
for (int i = 0; i < j; i++) {
|
||||
if (i == 0) {
|
||||
if (displayMetric) {
|
||||
tempcstr = "tempc";
|
||||
} else {
|
||||
tempcstr = "tempf";
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
if (displayMetric) {
|
||||
tempcstr = "tempc" + (String)i;
|
||||
} else {
|
||||
tempcstr = "tempf" + (String)i;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.containsKey(tempcstr)) {
|
||||
char temp[5];
|
||||
float temperature = data[tempcstr];
|
||||
dtostrf(temperature, 3, 1, temp);
|
||||
properties[i - 1] = "tp" + (String)i + ": " + (String)temp;
|
||||
if (displayMetric) {
|
||||
properties[i - 1] += "°C ";
|
||||
} else {
|
||||
properties[i - 1] += "°F ";
|
||||
}
|
||||
} else {
|
||||
properties[i - 1] = "tp" + (String)i + ": " + "off ";
|
||||
}
|
||||
}
|
||||
} else if (data["type"] == "BODY") {
|
||||
if (data.containsKey("steps")) {
|
||||
property++;
|
||||
int stepsint = data["steps"];
|
||||
char steps[5];
|
||||
itoa(stepsint, steps, 10);
|
||||
properties[property] = "steps: " + (String)steps + " ";
|
||||
// next line
|
||||
property++;
|
||||
}
|
||||
|
||||
if (data.containsKey("act_bpm")) {
|
||||
property++;
|
||||
int actbpmint = data["act_bpm"];
|
||||
char actbpm[3];
|
||||
itoa(actbpmint, actbpm, 10);
|
||||
properties[property] = "activity bpm: " + (String)actbpm + " ";
|
||||
}
|
||||
|
||||
if (data.containsKey("bpm")) {
|
||||
property++;
|
||||
int bpmint = data["bpm"];
|
||||
char bpm[3];
|
||||
itoa(bpmint, bpm, 10);
|
||||
properties[property] = "bpm: " + (String)bpm + " ";
|
||||
}
|
||||
} else if (data["type"] == "SCALE") {
|
||||
if (data.containsKey("weighing_mode")) {
|
||||
property++;
|
||||
String mode = data["weighing_mode"];
|
||||
properties[property] = mode + " ";
|
||||
// next line
|
||||
property++;
|
||||
}
|
||||
|
||||
if (data.containsKey("weight")) {
|
||||
property++;
|
||||
float weightf = data["weight"];
|
||||
char weight[7];
|
||||
dtostrf(weightf, 3, 1, weight);
|
||||
if (data.containsKey("unit")) {
|
||||
String unit = data["unit"];
|
||||
properties[property] = "weight: " + (String)weight + unit + " ";
|
||||
} else {
|
||||
properties[property] = "weight: " + (String)weight;
|
||||
}
|
||||
// next line
|
||||
property++;
|
||||
}
|
||||
|
||||
if (data.containsKey("impedance")) {
|
||||
property++;
|
||||
int impint = data["impedance"];
|
||||
char imp[3];
|
||||
itoa(impint, imp, 10);
|
||||
properties[property] = "impedance: " + (String)imp + "ohm ";
|
||||
}
|
||||
} else if (data["type"] == "UNIQ") {
|
||||
if (data["model_id"] == "M1017") {
|
||||
if (data.containsKey("lvl_cm")) {
|
||||
property++;
|
||||
char lvl[5];
|
||||
if (displayMetric) {
|
||||
float lvlf = data["lvl_cm"];
|
||||
dtostrf(lvlf, 3, 1, lvl);
|
||||
properties[property] = "level: " + (String)lvl + "cm ";
|
||||
} else {
|
||||
float lvlf = data["lvl_in"];
|
||||
dtostrf(lvlf, 3, 1, lvl);
|
||||
properties[property] = "level: " + (String)lvl + "\" ";
|
||||
}
|
||||
}
|
||||
|
||||
if (data.containsKey("quality")) {
|
||||
property++;
|
||||
int qualint = data["quality"];
|
||||
char qual[3];
|
||||
itoa(qualint, qual, 10);
|
||||
properties[property] = "qy: " + (String)qual + " ";
|
||||
}
|
||||
|
||||
if (data.containsKey("batt")) {
|
||||
property++;
|
||||
int battery = data["batt"];
|
||||
char batt[5];
|
||||
itoa(battery, batt, 10);
|
||||
properties[property] = "batt: " + (String)batt + "% ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line2 = properties[0] + properties[1];
|
||||
line3 = properties[2] + properties[3];
|
||||
line4 = properties[4] + properties[5];
|
||||
|
||||
if (!(line2 == "" && line3 == "" && line4 == "")) {
|
||||
// Line 1
|
||||
strlcpy(message->line1, data["model"], OLED_TEXT_WIDTH);
|
||||
|
||||
line2.toCharArray(message->line2, OLED_TEXT_WIDTH);
|
||||
line3.toCharArray(message->line3, OLED_TEXT_WIDTH);
|
||||
line4.toCharArray(message->line4, OLED_TEXT_WIDTH);
|
||||
|
||||
if (xQueueSend(displayQueue, (void*)&message, 0) != pdTRUE) {
|
||||
Log.error(F("[ SSD1306 ] displayQueue full, discarding signal %s" CR), message->title);
|
||||
free(message);
|
||||
} else {
|
||||
// Log.notice(F("Queued %s" CR), message->title);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
float humidity = data["hum"];
|
||||
if (data.containsKey("hum") && humidity <= 100 && humidity >= 0) {
|
||||
char hum[5];
|
||||
dtostrf(humidity, 3, 1, hum);
|
||||
line3 += "hum: " + (String)hum + "% ";
|
||||
}
|
||||
|
||||
line3.toCharArray(message->line3, OLED_TEXT_WIDTH);
|
||||
|
||||
// Line 4
|
||||
|
||||
String rssi = data["rssi"];
|
||||
String battery_ok = data["batt"];
|
||||
|
||||
String line4;
|
||||
if (data.containsKey("batt"))
|
||||
line4 += "batt: " + battery_ok + " ";
|
||||
|
||||
line4 += "rssi: " + rssi;
|
||||
line4.toCharArray(message->line4, OLED_TEXT_WIDTH);
|
||||
|
||||
// Queue completed message
|
||||
|
||||
if (xQueueSend(displayQueue, (void*)&message, 0) != pdTRUE) {
|
||||
Log.error(F("[ SSD1306 ] displayQueue full, discarding signal %s" CR), message->title);
|
||||
free(message);
|
||||
} else {
|
||||
// Log.notice(F("Queued %s" CR), message->title);
|
||||
}
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
default:
|
||||
|
||||
+4
-3
@@ -257,9 +257,6 @@ void pubBTMainCore(JsonObject& data, bool haPresenceEnabled = true) {
|
||||
topic = BTConfig.extDecoderTopic; // If external decoder, use this topic to send data
|
||||
topic = subjectBTtoMQTT + String("/") + topic;
|
||||
pub((char*)topic.c_str(), data);
|
||||
if (data.containsKey("model") || data.containsKey("distance")) { // Only display sensor data
|
||||
pubOled((char*)topic.c_str(), data);
|
||||
}
|
||||
}
|
||||
if (haPresenceEnabled && data.containsKey("distance")) {
|
||||
if (data.containsKey("servicedatauuid"))
|
||||
@@ -982,6 +979,10 @@ void launchBTDiscovery(bool overrideDiscovery) {
|
||||
void PublishDeviceData(JsonObject& BLEdata, bool processBLEData) {
|
||||
if (abs((int)BLEdata["rssi"] | 0) < abs(BTConfig.minRssi)) { // process only the devices close enough
|
||||
if (processBLEData) process_bledata(BLEdata);
|
||||
String topic = subjectBTtoMQTT;
|
||||
if (BLEdata.containsKey("model") || BLEdata.containsKey("distance")) { // Only display sensor data
|
||||
pubOled((char*)topic.c_str(), BLEdata);
|
||||
}
|
||||
if (!BTConfig.pubAdvData) {
|
||||
BLEdata.remove("servicedatauuid");
|
||||
BLEdata.remove("servicedata");
|
||||
|
||||
@@ -61,7 +61,9 @@ extra_configs =
|
||||
;default_envs = esp32doitv1-aithinker-r01-sx1278
|
||||
;default_envs = esp32dev-rtl_433
|
||||
;default_envs = heltec-rtl_433
|
||||
;default_envs = heltec-ble
|
||||
;default_envs = lilygo-rtl_433
|
||||
;default_envs = lilygo-ble
|
||||
;default_envs = esp32dev-multi_receiver
|
||||
;default_envs = tinypico-ble
|
||||
;default_envs = ttgo-lora32-v1-868
|
||||
|
||||
Reference in new issue
Block a user