Buongiorno, allego codice per la lettura temperatura/umidità di 2 sensori SwitchBot attraverso BLE e ESP32.
L'ESP32 è un C6 con display da 1.47 pollici. Uso la libreria LovyanGFX per la grafica.
I due sensori sono un "MeterTH S1 (con display)" e un "W3400010 (senza display)"
In casa ho un Hub Mini SwitchBot per Alexa. Ma la lettura viene fatta in base ai msg BLE spediti dai sensori.
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <LovyanGFX.hpp>
// Classe dedicata a Waveshare ESP32-C6 + ST7789 172x320
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ST7789 _panel_instance; // Driver ST7789
lgfx::Bus_SPI _bus_instance; // Bus SPI
lgfx::Light_PWM _light_instance; // Backlight PWM
public:
LGFX(void)
{
// === CONFIGURAZIONE BUS SPI (FSPI - unico bus su C6) ===
auto cfg_bus = _bus_instance.config();
cfg_bus.spi_host = SPI2_HOST; // FSPI su ESP32-C6
cfg_bus.pin_sclk = 7; // SCLK
cfg_bus.pin_mosi = 6; // MOSI
cfg_bus.pin_miso = -1; // MISO non connesso
cfg_bus.pin_dc = 15; // DC
cfg_bus.freq_write = 40000000; // 40MHz (come da tuo Setup72)
cfg_bus.freq_read = 20000000; // 20MHz
_bus_instance.config(cfg_bus);
_panel_instance.setBus(&_bus_instance);
// === CONFIGURAZIONE PANNELLO ST7789 172x320 ===
auto cfg_panel = _panel_instance.config();
cfg_panel.pin_cs = 14; // CS
cfg_panel.pin_rst = 21; // RST
cfg_panel.panel_width = 172; // Larghezza
cfg_panel.panel_height = 320; // Altezza
cfg_panel.offset_x = 34; // Offset 0 (tipico per questa board)
cfg_panel.offset_y = 0; // Offset 0
cfg_panel.offset_rotation = 0; // Nessuna rotazione hardware
cfg_panel.rgb_order = false;
cfg_panel.invert = true;
_panel_instance.config(cfg_panel);
// === CONFIGURAZIONE BACKLIGHT (PWM su GPIO 22) ===
auto cfg_light = _light_instance.config();
cfg_light.pin_bl = 22; // BL
cfg_light.invert = false; // NON invertire
cfg_light.freq = 44100; // Frequenza PWM
cfg_light.pwm_channel = 7; // Canale PWM
_light_instance.config(cfg_light);
_panel_instance.setLight(&_light_instance);
setPanel(&_panel_instance);
}
};
LGFX tft; // Istanza del display
String sensorAddress1 = "d8:bf:c2:06:3e:28"; // MeterTH S1 (con display)
String sensorAddress2 = "ff:06:59:4d:40:b5"; // W3400010 (senza display)
String sensorAddress3 = "d1:67:32:05:cc:af"; // Hub mini
float temp1 = 0, temp2 = 0;
int hum1 = 0, hum2 = 0;
int batt1 = 0, batt2 = 0;
bool sensore1Trovato = false;
bool sensore2Trovato = false;
const int scanTime = 5;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice advertisedDevice)
{ uint8_t battery = 0, lunS = 0, lunM = 0, humidity = 0, temp_integer = 0 , temp_decimal = 0;
byte sensor=0;
float temp = 0;
bool is_positive;
String deviceAddress = advertisedDevice.getAddress().toString().c_str();
if (deviceAddress.equalsIgnoreCase(sensorAddress1)) sensor=1;
if (deviceAddress.equalsIgnoreCase(sensorAddress2)) sensor=2;
// if (deviceAddress.equalsIgnoreCase(sensorAddress3)) sensor=3;
if(sensor==0) return;
String serviceDataStr = advertisedDevice.getServiceData();
const char* serData = serviceDataStr.c_str();
if (advertisedDevice.haveServiceData()) // --- Service Data (BATTERIA) ---
{ lunS = serviceDataStr.length();
if (lunS >= 3)
{ if (sensor == 2 && serData[0] == 0x77) battery = serData[2] & 0x7F;
if (sensor == 1 && serData[0] == 0x54) battery = serData[2] & 0x7F; // Provvisiorio
}
}
// --- Manufacturer Data (TEMPERATURA e UMIDITÀ) ---
String strManufacturerData = advertisedDevice.getManufacturerData();
lunM = strManufacturerData.length();
Serial.print("+ Sensore "); Serial.print(sensor);
Serial.print(": "); Serial.print(deviceAddress);
Serial.print(" Ser_len: "); Serial.print(lunS);
Serial.print(" Ser Raw: ");
for (int i = 0; i < lunS; i++)
{ if (serData[i] < 0x10) Serial.print("0");
Serial.print(serData[i], HEX); Serial.print(" ");
}
Serial.print(" Man_len: "); Serial.print(lunM);
// Stampa raw per debug
if (lunM < 5) return;
Serial.print(" Man Raw: ");
uint8_t * manData = (uint8_t*)strManufacturerData.c_str();
for (int i = 0; i < lunM; i++)
{ if (manData[i] < 0x10) Serial.print("0");
Serial.print(manData[i], HEX); Serial.print(" ");
}
Serial.println();
// Verifica manufacturer ID (0x69 0x09) SwitchBot
if (manData[0] != 0x69 || manData[1] != 0x09) return;
switch(sensor)
{ case 2: // W3400010
if(lunM == 14)
{ if (battery == 0) battery = manData[8] & 0x7F; // Forse batteria qui?
temp_decimal = manData[10] & 0x0F;
temp_integer = manData[11] & 0x7F;
is_positive = (manData[11] & 0x80);
temp = temp_integer + (temp_decimal * 0.1);
if (!is_positive) temp = -temp;
humidity = manData[12] & 0x7F;
temp2 = temp; hum2 = (int)humidity; batt2 = (int)battery; sensore2Trovato = true;
}
break;
case 1: // MeterTH S1 (con display)
if (lunM == 13 && lunS>5) // Meter
{ // Umidità - dal byte 12
humidity = manData[12] & 0x7F;
is_positive = (serData[4] & 0x80) == 0;
temp_integer = serData[4] & 0x7F;
temp_decimal = serData[3] & 0x0F;
temp = temp_integer + (temp_decimal * 0.1);
temp1 = temp; hum1 = (int)humidity; batt1 = (int)battery; sensore1Trovato = true;
}
break;
} // switch
}
};
void setup()
{ Serial.begin(115200);
delay(1000);
// Inizializzazione display
tft.init();
tft.setRotation(1); // 0=USB a sinistra, 1=USB a destra (ritratto) 1 orizzontale 0=verticale
tft.setBrightness(200);
Serial.println("=== SCANNER SENSORI SWITCHBOT DOPPIO MODELLO ===");
BLEDevice::init("");
}
void loop()
{ tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setTextSize(2);
tft.drawString("Sensori SwitchBot:", 10, 10);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
sensore1Trovato = false;
sensore2Trovato = false;
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->setInterval(100);
pBLEScan->setWindow(99);
Serial.println("\n--- Scansione in corso ---");
BLEScanResults* foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Dispositivi trovati: ");
Serial.println(foundDevices->getCount());
pBLEScan->clearResults();
char buf[20];
if (sensore1Trovato)
{ snprintf(buf,sizeof(buf),"S1: %3.1fC %2d%% %3d%%",temp1,hum1,batt1);
tft.drawString(buf, 10, 40);
Serial.print("* Sensore 1 (MeterTH S1):");
Serial.print(" Temperatura: "); Serial.print(temp1, 1); Serial.print(" °C");
Serial.print(" Umidità: "); Serial.print(hum1, 0); Serial.print(" %");
Serial.print(" Batteria: "); Serial.print(batt1, 0); Serial.println(" %");
}
if (sensore2Trovato)
{ snprintf(buf,sizeof(buf),"S2: %3.1fC %2d%% %3d%%",temp2,hum2,batt2);
tft.drawString(buf, 10, 80);
Serial.print("* Sensore 2 (W3400010)..:");
Serial.print(" Temperatura: "); Serial.print(temp2, 1); Serial.print(" °C");
Serial.print(" Umidità: "); Serial.print(hum2, 0); Serial.print(" %");
Serial.print(" Batteria: "); Serial.print(batt2, 0); Serial.println(" %");
}
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.drawString("Attendo 30 secondi...", 10, 120);
Serial.println("\n Attendo 30 secondi...");
delay(30000);
}
