[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:
DigiH authored and GitHub committed 2023-03-01 15:09:45 -06:00
1 parent a6e0f6094c
commit c77a16867d
5 files changed
+362 -51

No files matched your search

+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");
+2
View File
@@ -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