salut
pour ceux qui veulent voici le début de code
il y a encore du taf , je ne suis pas sur de le faire ce WE mais je devait finir lundi
le code permet de détecter automatiquement le justsalt
donc Wifi et serveur MQTT a remplir
#include <Arduino.h>
/** Electolyseur JustSalt & co
*
* Passerelle Bt Justsalt to Mqtt
*
* Created: Mai 2025
* Author: Ricky
*
*/
#include <NimBLEDevice.h>
#include <ArduinoHA.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
const char* version = "0.0.1";
// Update these with values suitable for your wifi network.
const char* ssid = "wifi";
const char* password = "xxxxxxxxxxxxxxxxxxxx";
//Home Assistant integration
// configure here your HA params for connection to MQTT server
#define BROKER_ADDR IPAddress(192,168,50,11)
#define BROKER_USERNAME "" // replace with your credentials
#define BROKER_PASSWORD ""
//Unique device for HA integration
const byte deviceUniqID[] = { 0x94, 0xDE, 0xB8, 0xA1, 0x1A, 0xAC };
//justsalt service and char UUID
// The remote service we wish to connect to.
static BLEUUID serviceUUID("09912756-7b32-4629-aeb1-b309d9a338ae");
// The characteristic of the remote service we are interested in.
static BLEUUID charUUID("ef785c24-22bb-463d-b651-0b7445ba091c");
WiFiClient wifiMQTT;
WiFiClient telnet;
WiFiServer telnetServer(23);
unsigned long previousMillis = 0;
unsigned long interval = 30000;
void scanEndedCB(NimBLEScanResults results);
void setup_wifi();
void reconnect_wifi();
void setupHaIntegration();
void setup_telnet();
void cb_handleTelnet();
void cb_loopHaIntegration();
static NimBLEAdvertisedDevice* advDevice;
static bool doConnect = false;
static uint32_t scanTime = 0; /** 0 = scan forever */
struct trame_value {
uint8_t V_id_00;
float V_id_01;
float V_id_02;
float V_id_03;
float V_id_06;
float V_id_08;
float V_id_09;
float V_id_0A;
float V_id_0B;
float V_id_0C;
float V_id_0D;
float V_id_0E;
float V_id_0F;
float V_id_10;
float V_id_11;
float V_id_12;
float V_id_13;
float V_id_1F;
float V_id_28;
float V_id_29;
float V_id_2A;
float V_id_30;
float V_id_31;
float V_id_32;
float V_id_33;
float V_id_35;
float V_id_37;
float V_id_39;
float V_id_50;
float V_id_51;
float V_id_5F;
float V_id_69;
float V_id_6A;
float V_id_8F;
String V_id_90;
String V_id_91;
float V_id_92;
uint8_t V_id_93;
bool V_id_93_b0;
bool V_id_93_b1;
bool V_id_93_b2;
bool V_id_93_b3;
bool V_id_93_b4;
bool V_id_93_b5;
bool V_id_93_b6;
bool V_id_93_b7;
float V_id_94;
uint16_t V_id_95;
float V_id_96;
float V_id_97;
String V_id_99;
String V_id_9A;
float V_id_9B;
float V_id_9C;
String V_id_9D;
String V_id_A3;
float V_id_B0;
String V_id_B1;
String V_id_D0;
float V_id_D1;
String V_id_E1;
String V_id_E2;
String V_id_E4;
float V_id_FE;
};
struct trame_value Electrovalue;
HADevice deviceHA;
// dernier paramètre pour le nombre de sensorMQTT à lister
HAMqtt mqtt(wifiMQTT, deviceHA, 70);
//List of sensor for HA
HASensorNumber wifiStrength("pool_wifi_strength", HASensorNumber::PrecisionP2);
HASensor justsaltIp("pool_ip");
HASensorNumber temp("pool_temp",HASensorNumber::PrecisionP1) ;
HASensorNumber ph("pool_ph",HASensorNumber::PrecisionP1);
HASensorNumber orp("pool_orp",HASensorNumber::PrecisionP0);
HASensorNumber sel("pool_sel",HASensorNumber::PrecisionP1);
HASensorNumber vol("pool_vol",HASensorNumber::PrecisionP0);
HASensorNumber phconsigne("pool_ph_consigne",HASensorNumber::PrecisionP1);
HASensorNumber acide("pool_acide",HASensorNumber::PrecisionP1);
HASensorNumber prod("pool_prod",HASensorNumber::PrecisionP0);
HASensorNumber orpconsigne("pool_orp_consigne",HASensorNumber::PrecisionP0);
HASensorNumber orpalarme("pool_orp_alarme",HASensorNumber::PrecisionP0);
HASensorNumber inversion("pool_inversion",HASensorNumber::PrecisionP0);
HASensorNumber temp02("pool_temp02",HASensorNumber::PrecisionP0);
HASensorNumber temp03("pool_temp03",HASensorNumber::PrecisionP0);
HASensorNumber temp08("pool_temp08",HASensorNumber::PrecisionP0);
HASensorNumber temp0B("pool_temp0B",HASensorNumber::PrecisionP0);
HASensorNumber temp0C("pool_temp0C",HASensorNumber::PrecisionP0);
HASensorNumber temp0D("pool_temp0D",HASensorNumber::PrecisionP0);
HASensorNumber temp0E("pool_temp0E",HASensorNumber::PrecisionP0);
HASensorNumber temp0F("pool_temp0F",HASensorNumber::PrecisionP0);
HASensorNumber temp10("pool_temp10",HASensorNumber::PrecisionP0);
HASensorNumber temp12("pool_temp12",HASensorNumber::PrecisionP0);
HASensorNumber temp13("pool_temp13",HASensorNumber::PrecisionP0);
HASensorNumber temp1F("pool_temp1F",HASensorNumber::PrecisionP0);
HASensorNumber temp28("pool_temp28",HASensorNumber::PrecisionP0);
HASensorNumber temp29("pool_temp29",HASensorNumber::PrecisionP0);
HASensorNumber temp2A("pool_temp2A",HASensorNumber::PrecisionP0);
HASensorNumber temp31("pool_temp31",HASensorNumber::PrecisionP0);
HASensorNumber temp50("pool_temp50",HASensorNumber::PrecisionP0);
HASensorNumber temp51("pool_temp51",HASensorNumber::PrecisionP0);
HASensorNumber temp5F("pool_temp5F",HASensorNumber::PrecisionP0);
HASensorNumber temp69("pool_temp69",HASensorNumber::PrecisionP0);
HASensorNumber temp6A("pool_temp6A",HASensorNumber::PrecisionP0);
HASensorNumber temp8F("pool_temp8F",HASensorNumber::PrecisionP0);
HASensor temp90("pool_temp90");
HASensor temp91("pool_temp91");
HASensorNumber temp92("pool_temp92",HASensorNumber::PrecisionP0);
HASensorNumber temp93("pool_temp93",HASensorNumber::PrecisionP0);
HABinarySensor temp93B0("false93B0");
HABinarySensor temp93B1("false93B1");
HABinarySensor temp93B2("false93B2");
HABinarySensor temp93B3("false93B3");
HABinarySensor temp93B4("false93B4");
HABinarySensor temp93B5("false93B5");
HABinarySensor temp93B6("false93B6");
HABinarySensor temp93B7("false93B7");
HASensorNumber temp94("pool_temp94",HASensorNumber::PrecisionP0);
void cb_handleTelnet() {
if (telnetServer.hasClient()) {
if (!telnet || !telnet.connected()) {
if (telnet) telnet.stop();
telnet = telnetServer.available();
} else {
telnetServer.available().stop();
}
}
}
void cb_loopAvaibilityMQTT(){
mqtt.loop();
//remove setAvaibility to use native check of Ha integration Shared availability
deviceHA.setAvailability(true);
//savoir si la connexion bluetooth est OK ou si le justsalt n'est pas sous tension.
//bluetoothConnected.setState(connected);
}
void cb_loopHaIntegration(){
//mqtt.loop();
//remove setAvaibility to use native check of Ha integration Shared availability
//deviceHA.setAvailability(true);
wifiStrength.setValue(WiFi.RSSI());
justsaltIp.setValue(WiFi.localIP().toString().c_str());
ph.setValue(Electrovalue.V_id_01);
temp02.setValue(Electrovalue.V_id_02);
temp03.setValue(Electrovalue.V_id_03);
orp.setValue(Electrovalue.V_id_06);
temp08.setValue(Electrovalue.V_id_08);
temp.setValue(Electrovalue.V_id_09);
sel.setValue(Electrovalue.V_id_0A);
temp0B.setValue(Electrovalue.V_id_0B);
temp0C.setValue(Electrovalue.V_id_0C);
temp0D.setValue(Electrovalue.V_id_0D);
temp0E.setValue(Electrovalue.V_id_0E);
temp0F.setValue(Electrovalue.V_id_0F);
temp10.setValue(Electrovalue.V_id_10);
vol.setValue(Electrovalue.V_id_11);
temp12.setValue(Electrovalue.V_id_12);
temp13.setValue(Electrovalue.V_id_13);
temp1F.setValue(Electrovalue.V_id_1F);
temp28.setValue(Electrovalue.V_id_28);
temp29.setValue(Electrovalue.V_id_29);
phconsigne.setValue(Electrovalue.V_id_30);
temp31.setValue(Electrovalue.V_id_31);
acide.setValue(Electrovalue.V_id_32);
prod.setValue(Electrovalue.V_id_33);
orpconsigne.setValue(Electrovalue.V_id_35);
orpalarme.setValue(Electrovalue.V_id_37);
inversion.setValue(Electrovalue.V_id_39);
temp50.setValue(Electrovalue.V_id_50);
temp51.setValue(Electrovalue.V_id_51);
temp5F.setValue(Electrovalue.V_id_5F);
temp69.setValue(Electrovalue.V_id_69);
temp6A.setValue(Electrovalue.V_id_6A);
temp8F.setValue(Electrovalue.V_id_8F);
//temp90.setValue(Electrovalue.V_id_90);
//temp91.setValue(Electrovalue.V_id_91);
temp92.setValue(Electrovalue.V_id_92);
temp93.setValue(Electrovalue.V_id_93);
temp93B0.setCurrentState(Electrovalue.V_id_93_b0);
temp93B1.setCurrentState(Electrovalue.V_id_93_b1);
temp93B2.setCurrentState(Electrovalue.V_id_93_b2);
temp93B3.setCurrentState(Electrovalue.V_id_93_b3);
temp93B4.setCurrentState(Electrovalue.V_id_93_b4);
temp93B5.setCurrentState(Electrovalue.V_id_93_b5);
temp93B6.setCurrentState(Electrovalue.V_id_93_b6);
temp93B7.setCurrentState(Electrovalue.V_id_93_b7);
temp94.setValue(Electrovalue.V_id_94);
}
void setupHaIntegration(){
//HA integration
deviceHA.setUniqueId(deviceUniqID, sizeof(deviceUniqID));
deviceHA.setName("justsalt");
deviceHA.setSoftwareVersion(version);
deviceHA.setModel("Electolyseur");
deviceHA.setManufacturer("ricky");
// This method enables availability for all device types registered on the device.
// For example, if you have 5 sensors on the same device, you can enable
// shared availability and change availability state of all sensors using
// single method call "device.setAvailability(false|true)"
deviceHA.enableSharedAvailability();
// Optionally, you can enable MQTT LWT feature. If device will lose connection
// to the broker, all device types related to it will be marked as offline in
// the Home Assistant Panel.
deviceHA.enableLastWill();
wifiStrength.setName("Pool wifi Strength");
wifiStrength.setDeviceClass("signal_strength");
wifiStrength.setUnitOfMeasurement("dB");
justsaltIp.setName("justsalt IP");
justsaltIp.setIcon("mdi:ip-network");
// HA integration List of Sensor
temp.setName("Water temp");
temp.setUnitOfMeasurement("°C");
temp.setDeviceClass("temperature");
temp.setIcon("mdi:thermometer");
orp.setName("orp");
orp.setUnitOfMeasurement("mV");
orp.setIcon("mdi:alpha-r-box-outline");
ph.setName("PH");
ph.setIcon("mdi:ph");
ph.setUnitOfMeasurement("ph");
sel.setName("Sel");
sel.setUnitOfMeasurement("g/L");
sel.setIcon("mdi:alpha-s-box-outline");
phconsigne.setName("PH Consigne");
phconsigne.setIcon("mdi:ph");
phconsigne.setUnitOfMeasurement("ph");
orpconsigne.setName("orp Consigne");
orpconsigne.setUnitOfMeasurement("mV");
orpconsigne.setIcon("mdi:alpha-r-box-outline");
orpalarme.setName("orp Alarme");
orpalarme.setUnitOfMeasurement("h");
orpalarme.setIcon("mdi:alpha-r-box-outline");
vol.setName("volume piscine");
vol.setUnitOfMeasurement("m3");
vol.setIcon("mdi:alpha-r-box-outline");
acide.setName("taux Acide");
acide.setUnitOfMeasurement("%");
acide.setStateClass("measurement");
acide.setIcon("mdi:Skull-Crossbones");
prod.setName("production");
prod.setUnitOfMeasurement("%");
prod.setStateClass("measurement");
prod.setIcon("mdi:Cog-Outline");
inversion.setName("inversion");
inversion.setUnitOfMeasurement("%");
temp02.setName("temp02");
temp03.setName("temp03");
temp08.setName("temp08");
temp0B.setName("temp0B");
temp0C.setName("temp0C");
temp0D.setName("temp0D");
temp0E.setName("temp0E");
temp0F.setName("temp0F");
temp10.setName("temp10");
temp12.setName("temp12");
temp13.setName("temp13");
temp1F.setName("temp1F");
temp28.setName("temp28");
temp29.setName("temp29");
temp31.setName("temp31");
temp50.setName("temp50");
temp51.setName("temp51");
temp5F.setName("temp5F");
temp69.setName("temp69");
temp6A.setName("temp6A");
temp8F.setName("temp8F");
temp90.setName("temp90");
temp91.setName("temp91");
temp92.setName("temp92");
temp93.setName("temp93");
temp93B0.setName("temp93B0");
temp93B1.setName("temp93B1");
temp93B2.setName("temp93B2");
temp93B3.setName("temp93B3");
temp93B4.setName("temp93B4");
temp93B5.setName("temp93B5");
temp93B6.setName("temp93B6");
temp93B7.setName("temp93B7");
temp94.setName("temp94");
// bluetoothConnected.setName("Bluetooth Status");
mqtt.begin( BROKER_ADDR, BROKER_USERNAME, BROKER_PASSWORD );
}
void setup_telnet(){
Serial.print("Ready! Use 'telnet ");
Serial.print(WiFi.localIP());
Serial.println(" 23' to connect");
}
void reconnect_wifi(){
unsigned long currentMillis = millis();
// if WiFi is down, try reconnecting every CHECK_WIFI_TIME seconds
if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >=interval)) {
Serial.print(millis());
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WiFi.reconnect();
#ifdef SYSLOG_SERVER
syslog.log(LOG_INFO, "WIFI lost and reconnect automatically");
#endif
previousMillis = currentMillis;
}
}
void setup_wifi() {
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
WiFi.mode(WIFI_STA);
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
/** None of these are required as they will be handled by the library with defaults. **
** Remove as you see fit for your needs */
class ClientCallbacks : public NimBLEClientCallbacks {
void onConnect(NimBLEClient* pClient) {
Serial.println("Connected");
/** After connection we should change the parameters if we don't need fast response times.
* These settings are 150ms interval, 0 latency, 450ms timout.
* Timeout should be a multiple of the interval, minimum is 100ms.
* I find a multiple of 3-5 * the interval works best for quick response/reconnect.
* Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 60 * 10ms = 600ms timeout
*/
pClient->updateConnParams(120,120,0,60);
};
void onDisconnect(NimBLEClient* pClient) {
Serial.print(pClient->getPeerAddress().toString().c_str());
Serial.println(" Disconnected - Starting scan");
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
};
/** Called when the peripheral requests a change to the connection parameters.
* Return true to accept and apply them or false to reject and keep
* the currently used parameters. Default will return true.
*/
bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) {
if(params->itvl_min < 24) { /** 1.25ms units */
return false;
} else if(params->itvl_max > 40) { /** 1.25ms units */
return false;
} else if(params->latency > 2) { /** Number of intervals allowed to skip */
return false;
} else if(params->supervision_timeout > 100) { /** 10ms units */
return false;
}
return true;
};
/********************* Security handled here **********************
****** Note: these are the same return values as defaults ********/
uint32_t onPassKeyRequest(){
Serial.println("Client Passkey Request");
/** return the passkey to send to the server */
return 123456;
};
bool onConfirmPIN(uint32_t pass_key){
Serial.print("The passkey YES/NO number: ");
Serial.println(pass_key);
/** Return false if passkeys don't match. */
return true;
};
/** Pairing process complete, we can check the results in ble_gap_conn_desc */
void onAuthenticationComplete(ble_gap_conn_desc* desc){
if(!desc->sec_state.encrypted) {
Serial.println("Encrypt connection failed - disconnecting");
/** Find the client with the connection handle provided in desc */
NimBLEDevice::getClientByID(desc->conn_handle)->disconnect();
return;
}
};
};
/** Define a class to handle the callbacks when advertisments are received */
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
Serial.print("Advertised Device found: ");
Serial.println(advertisedDevice->toString().c_str());
char* manufacturerdata = BLEUtils::buildHexData(NULL, (uint8_t*)advertisedDevice->getManufacturerData().data(), advertisedDevice->getManufacturerData().length());
Serial.println(manufacturerdata);
if ((strcmp(manufacturerdata , "ffff00202020202020202020202020202020202020") == 0) or (strcmp(manufacturerdata , "ffff01202020202020202020202020202020202020") == 0)) {
//if(advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD")))
//{
Serial.println("Found Our device");
/** stop scan before connecting */
NimBLEDevice::getScan()->stop();
/** Save the device reference in a global for the client to use*/
advDevice = advertisedDevice;
/** Ready to connect now */
doConnect = true;
}
};
};
/** Notification / Indication receiving handler callback */
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
std::string str = (isNotify == true) ? "Notification" : "Indication";
str += " from ";
/** NimBLEAddress and NimBLEUUID have std::string operators */
str += std::string(pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress());
str += ": Service = " + std::string(pRemoteCharacteristic->getRemoteService()->getUUID());
str += ", Characteristic = " + std::string(pRemoteCharacteristic->getUUID());
str += ", Value = " + std::string((char*)pData, length);
Serial.println(str.c_str());
Serial.print(" taille = ");
Serial.println(length);
if (length > 6){
int index =3;
while (index +2 < length) {
uint8_t idvaleur = pData[index];
int taillevaleur = pData[index + 1 ];
switch (idvaleur) {
case 0x00: {
Electrovalue.V_id_00 = 0;
}break;
case 0x01: {
uint8_t phhex = pData[index + 2];
float ph = static_cast<float>(phhex)/10;
Electrovalue.V_id_01 = ph;
Serial.print("PH : " );
Serial.println(ph);
}break;
case 0x02: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_02 = temp;
Serial.print("temp02 : " );
Serial.println(temp);
}break;
case 0x03: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_03 = temp;
}break;
case 0x06: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index + 3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_06 = temp;
Serial.print("ORP : " );
Serial.println(temp);
}break;
case 0x08: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_08 = temp;
}break;
case 0x09: {
uint16_t tempeauhex = ((pData[index + 2]<< 8) + (pData[index +3]));
float tempeau = static_cast<float>(tempeauhex)/10;
Electrovalue.V_id_09 = tempeau;
}break;
case 0x0A: {
uint8_t selhex = pData[index + 2] ;
float sel = static_cast<float>(selhex)/10;
Electrovalue.V_id_0A = sel;
}break;
case 0x0B: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_0B = temp;
}break;
case 0x0C: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_0C = temp;
}break;
case 0x0D: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_0D = temp;
}break;
case 0x0E: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_0E = temp;
}break;
case 0x0F: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_0F = temp;
}break;
case 0x10: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_10 = temp;
}break;
case 0x11: {
uint16_t volhex = ((pData[index + 2]<< 8) + (pData[index +3]));
float vol = static_cast<float>(volhex);
Electrovalue.V_id_11 = vol;
}break;
case 0x12: {
uint32_t temphex = (pData[index + 2]<< 24) + (pData[index + 3]<< 16)+ (pData[index + 4]<< 8) + (pData[index +5]);
float temp = static_cast<float>(temphex);
Electrovalue.V_id_12 = temp;
}break;
case 0x13: {
uint32_t temphex = (pData[index + 2]<< 24) + (pData[index + 3]<< 16)+ (pData[index + 4]<< 8) + (pData[index +5]);
float temp = static_cast<float>(temphex);
//std::string tempstr = value_accuracy_to_string (temp,0);
Electrovalue.V_id_13 = temp;
}break;
case 0x1F: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_1F = temp;
}break;
case 0x28: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_28 = temp;
}break;
case 0x29: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_29 = temp;
}break;
case 0x2A: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_2A = temp;
}break;
case 0x30: {
uint8_t phchex = pData[index + 2] ;
float phc = static_cast<float>(phchex)/10;
Electrovalue.V_id_30 = phc;
}break;
case 0x31: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_31 = temp;
}break;
case 0x32: {
uint8_t acidehex = pData[index + 2] ;
float acide = static_cast<float>(acidehex);
Electrovalue.V_id_32 = acide;
}break;
case 0x33: {
uint8_t prodhex = pData[index + 2] ;
float prod = static_cast<float>(prodhex);
Electrovalue.V_id_33 = prod;
}break;
case 0x35: {
uint8_t orpchex = pData[index + 2] ;
float orpc = static_cast<float>(orpchex)*10;
Electrovalue.V_id_35 = orpc;
}break;
case 0x37: {
uint8_t alarmeorphex = pData[index + 2] ;
float alarmeorp = static_cast<float>(alarmeorphex);
Electrovalue.V_id_37 = alarmeorp;
}break;
case 0x39: {
uint8_t inversionhex = pData[index + 2] ;
float inversionval = static_cast<float>(inversionhex);
Electrovalue.V_id_39 = inversionval;
}break;
case 0x50: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_50 = temp;
}break;
case 0x51: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_51 = temp;
}break;
case 0x5F: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_5F = temp;
}break;
case 0x69: {
uint32_t temphex = (pData[index + 2]<< 24) + (pData[index + 3]<< 16)+ (pData[index + 4]<< 8) + (pData[index +5]);
float temp = static_cast<float>(temphex);
Electrovalue.V_id_69 = temp;
}break;
case 0x6A: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_6A = temp;
}break;
case 0x8F: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_8F = temp;
}break;
case 0x90: {
// 90.08.00.00.00.00.00.00.00.14.
std::string tempstring = "";
for ( int i = index + 2; i < index + 2 + taillevaleur ; i++ ) {
Serial.print( "data: " );
Serial.println( pData[i], HEX );
tempstring += pData[i];
}
temp90.setValue(tempstring.c_str());
//Electrovalue.V_id_90 = tempstring.c_str();
}break;
case 0x91: {
// 91.08.00.00.00.00.00.06.6F.C3.
std::string tempstring = "";
for ( int i = index + 2; i < index + 2 + taillevaleur ; i++ ) {
Serial.print( "data: " );
Serial.println( pData[i], HEX );
tempstring += pData[i];
}
temp91.setValue(tempstring.c_str());
}break;
case 0x92: {
uint8_t temphex = pData[index + 2];
float temp = static_cast<float>(temphex);
Electrovalue.V_id_92 = temp;
}break;
case 0x93: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_93 = temp;
Electrovalue.V_id_93_b0 = (bool)((temphex & 0x01) );
Electrovalue.V_id_93_b1 = (bool)((temphex & 0x02) );
Electrovalue.V_id_93_b2 = (bool)((temphex & 0x04) );
Electrovalue.V_id_93_b3 = (bool)((temphex & 0x08) );
Electrovalue.V_id_93_b4 = (bool)((temphex & 0x10) );
Electrovalue.V_id_93_b5 = (bool)((temphex & 0x20) );
Electrovalue.V_id_93_b6 = (bool)((temphex & 0x40) );
Electrovalue.V_id_93_b7 = (bool)((temphex & 0x80) );
}break;
case 0x94: {
uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
float temp = static_cast<float>(temphex);
Electrovalue.V_id_94 = temp;
}break;
// case 0x95: {
// uint16_t idcodehex = (pData[index + 2]<< 24) + (pData[index + 3]<< 16)+ (pData[index + 4]<< 8) + (pData[index +5]);
// float idcodefloat = static_cast<float>(idcodehex);
// std::string idcodestr = value_accuracy_to_string (idcodefloat,0);
// id(idcode).publish_state(idcodestr);
// }break;
// case 0x96: {
// std::string verlog = rawhex.substr((index + 2 )* 2, 4);
// id(version_logiciel).publish_state(verlog);
// }break;
// case 0x97: {
// std::string slaveval = rawhex.substr((index + 2 )* 2, 4);
// id(slave).publish_state(slaveval);
// }break;
// case 0x99: {
// //99.16.47.45.4E.5F.30.35.32.32.2D.30.34.33.39.35.33.2D.30.30.33.00.00.00.
// std::string tempstring = value2.substr((index + 2 ), taillevaleur);
// id(JustSalt_nombt_textsensor).publish_state(tempstring.c_str());
// }break;
// case 0x9A: {
// //9A.10.30.35.32.32.2D.30.34.33.39.35.33.2D.30.30.33.00.
// std::string tempstring = value2.substr((index + 2 ), taillevaleur);
// id(JustSalt_sn_textsensor).publish_state(tempstring.c_str());
// }break;
// case 0x9B: {
// uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
// float temp = static_cast<float>(temphex);
// id(JustSalt_temp9b_sensor).publish_state(temp);
// }break;
// case 0x9C: {
// uint8_t temphex = ((pData[index + 2]<< 8) + (pData[index +3]));
// float temp = static_cast<float>(temphex);
// id(JustSalt_temp9c_sensor).publish_state(temp);
// }break;
// case 0x9D: {
// // 9D.08.00.00.00.00.00.00.01.FF
// std::string tempstring = rawhex.substr((index + 2 )* 2, 8);
// id(JustSalt_9d_textsensor).publish_state(tempstring);
// }break;
// case 0xA3: {
// // E1.0F.18.04.11.11.00.33.00.00.88.00.F8.00.00.00.00
// std::string tempstring = rawhex.substr((index + 2 )* 2, 15);
// id(JustSalt_a3_textsensor).publish_state(tempstring);
// }break;
// case 0xB0: {
// uint8_t temphex = pData[index + 2];
// float temp = static_cast<float>(temphex);
// id(JustSalt_tempb0_sensor).publish_state(temp);
// }break;
// case 0xB1: {
// std::string tempstring = rawhex.substr((index + 2 )* 2, 12);
// id(JustSalt_macbt_textsensor).publish_state(tempstring);
// }break;
// case 0xD0: {
// //D0.06.30.00.00.00.00.00
// std::string tempstring = rawhex.substr((index + 2 )* 2, 6);
// id(JustSalt_d0_textsensor).publish_state(tempstring);
// }break;
// case 0xD1: {
// uint8_t temphex = pData[index + 2];
// float temp = static_cast<float>(temphex);
// id(JustSalt_tempd1_sensor).publish_state(temp);
// }break;
// case 0xFE: {
// uint8_t temphex = pData[index + 2];
// float temp = static_cast<float>(temphex);
// id(JustSalt_tempfe_sensor).publish_state(temp);
// }break;
// case 0xE1: {
// // E1.0F.18.04.11.11.00.33.00.00.88.00.F8.00.00.00.00
// std::string tempstring = rawhex.substr((index + 2 )* 2, 30);
// id(JustSalt_e1_textsensor).publish_state(tempstring);
// //uint8_t temphex = ((pData[index + 9]<< 8) + (pData[index +10]));
// //float temp = static_cast<float>(temphex);
// //id(tempe1o89b0).publish_state((bool)((temphex & 0x01) ));
// //id(tempe1o89b1).publish_state((bool)((temphex & 0x02) ));
// //id(tempe1o89b2).publish_state((bool)((temphex & 0x04) ));
// //id(tempe1o89b3).publish_state((bool)((temphex & 0x08) ));
// //id(tempe1o89b4).publish_state((bool)((temphex & 0x10) ));
// //id(tempe1o89b5).publish_state((bool)((temphex & 0x20) ));
// //id(tempe1o89b6).publish_state((bool)((temphex & 0x40) ));
// //id(tempe1o89b7).publish_state((bool)((temphex & 0x80) ));
// }break;
// case 0xE2: {
// // E2.0F.18.04.16.0A.22.10.00.00.00.41.3E.DC.00.00.00
// std::string tempstring = rawhex.substr((index + 2 )* 2, 30);
// id(JustSalt_e2_textsensor).publish_state(tempstring);
// }break;
// case 0xE4: {
// // E4.0F.18.04.12.15.00.00.46.00.0B.13.00.00.00.00.00
// std::string tempstring = rawhex.substr((index + 2 )* 2, 30);
// id(JustSalt_e4_textsensor).publish_state(tempstring);
// }break;
default: {
Serial.print( "idvaleur Non implementee " );
Serial.println(idvaleur);
};
}
index = index + 2 + taillevaleur ;
}
Serial.println("fin traitement trame");
cb_loopHaIntegration();
Serial.println("fin cb_loopHaIntegration");
}
}
/** Callback to process the results of the last scan or restart it */
void scanEndedCB(NimBLEScanResults results){
Serial.println("Scan Ended");
}
/** Create a single global instance of the callback class to be used by all clients */
static ClientCallbacks clientCB;
/** Handles the provisioning of clients and connects / interfaces with the server */
bool connectToServer() {
NimBLEClient* pClient = nullptr;
/** Check if we have a client we should reuse first **/
if(NimBLEDevice::getClientListSize()) {
/** Special case when we already know this device, we send false as the
* second argument in connect() to prevent refreshing the service database.
* This saves considerable time and power.
*/
pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress());
if(pClient){
if(!pClient->connect(advDevice, false)) {
Serial.println("Reconnect failed");
return false;
}
Serial.println("Reconnected client");
}
/** We don't already have a client that knows this device,
* we will check for a client that is disconnected that we can use.
*/
else {
pClient = NimBLEDevice::getDisconnectedClient();
}
}
/** No client to reuse? Create a new one. */
if(!pClient) {
if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) {
Serial.println("Max clients reached - no more connections available");
return false;
}
pClient = NimBLEDevice::createClient();
Serial.println("New client created");
pClient->setClientCallbacks(&clientCB, false);
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout.
* These settings are safe for 3 clients to connect reliably, can go faster if you have less
* connections. Timeout should be a multiple of the interval, minimum is 100ms.
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout
*/
pClient->setConnectionParams(12,12,0,51);
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
pClient->setConnectTimeout(5);
if (!pClient->connect(advDevice)) {
/** Created a client but failed to connect, don't need to keep it as it has no data */
NimBLEDevice::deleteClient(pClient);
Serial.println("Failed to connect, deleted client");
return false;
}
}
if(!pClient->isConnected()) {
if (!pClient->connect(advDevice)) {
Serial.println("Failed to connect");
return false;
}
}
Serial.print("Connected to: ");
Serial.println(pClient->getPeerAddress().toString().c_str());
Serial.print("RSSI: ");
Serial.println(pClient->getRssi());
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
NimBLERemoteService* pSvc = nullptr;
NimBLERemoteCharacteristic* pChr = nullptr;
NimBLERemoteDescriptor* pDsc = nullptr;
//pSvc = pClient->getService("DEAD");
pSvc = pClient->getService("09912756-7b32-4629-aeb1-b309d9a338ae");
if(pSvc) { /** make sure it's not null */
//pChr = pSvc->getCharacteristic("BEEF");
pChr = pSvc->getCharacteristic("ef785c24-22bb-463d-b651-0b7445ba091c");
if(pChr) { /** make sure it's not null */
if(pChr->canRead()) {
std::string value = pChr->readValue();
Serial.print(pChr->getUUID().toString().c_str());
Serial.print(" Value: ");
Serial.println(value.c_str());
}
// if(pChr->canWrite()) {
// if(pChr->writeValue("Tasty")) {
// Serial.print("Wrote new value to: ");
// Serial.println(pChr->getUUID().toString().c_str());
// }
// else {
// /** Disconnect if write failed */
// pClient->disconnect();
// return false;
// }
// if(pChr->canRead()) {
// Serial.print("The value of: ");
// Serial.print(pChr->getUUID().toString().c_str());
// Serial.print(" is now: ");
// Serial.println(pChr->readValue().c_str());
// }
// }
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
* Unsubscribe parameter defaults are: response=false.
*/
if(pChr->canNotify()) {
//if(!pChr->registerForNotify(notifyCB)) {
if(!pChr->subscribe(true, notifyCB)) {
/** Disconnect if subscribe failed */
pClient->disconnect();
return false;
}
}
else if(pChr->canIndicate()) {
/** Send false as first argument to subscribe to indications instead of notifications */
//if(!pChr->registerForNotify(notifyCB, false)) {
if(!pChr->subscribe(false, notifyCB)) {
/** Disconnect if subscribe failed */
pClient->disconnect();
return false;
}
}
}
} else {
Serial.println("DEAD service not found.");
}
pSvc = pClient->getService("BAAD");
if(pSvc) { /** make sure it's not null */
pChr = pSvc->getCharacteristic("F00D");
if(pChr) { /** make sure it's not null */
if(pChr->canRead()) {
Serial.print(pChr->getUUID().toString().c_str());
Serial.print(" Value: ");
Serial.println(pChr->readValue().c_str());
}
pDsc = pChr->getDescriptor(NimBLEUUID("C01D"));
if(pDsc) { /** make sure it's not null */
Serial.print("Descriptor: ");
Serial.print(pDsc->getUUID().toString().c_str());
Serial.print(" Value: ");
Serial.println(pDsc->readValue().c_str());
}
if(pChr->canWrite()) {
if(pChr->writeValue("No tip!")) {
Serial.print("Wrote new value to: ");
Serial.println(pChr->getUUID().toString().c_str());
}
else {
/** Disconnect if write failed */
pClient->disconnect();
return false;
}
if(pChr->canRead()) {
Serial.print("The value of: ");
Serial.print(pChr->getUUID().toString().c_str());
Serial.print(" is now: ");
Serial.println(pChr->readValue().c_str());
}
}
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
* Unsubscribe parameter defaults are: response=false.
*/
if(pChr->canNotify()) {
//if(!pChr->registerForNotify(notifyCB)) {
if(!pChr->subscribe(true, notifyCB)) {
/** Disconnect if subscribe failed */
pClient->disconnect();
return false;
}
}
else if(pChr->canIndicate()) {
/** Send false as first argument to subscribe to indications instead of notifications */
//if(!pChr->registerForNotify(notifyCB, false)) {
if(!pChr->subscribe(false, notifyCB)) {
/** Disconnect if subscribe failed */
pClient->disconnect();
return false;
}
}
}
} else {
Serial.println("BAAD service not found.");
}
Serial.println("Done with this device!");
return true;
}
void setup (){
Serial.begin(115200);
setup_wifi();
setup_telnet();
setupHaIntegration();
Serial.println("Starting NimBLE Client");
/** Initialize NimBLE, no device name spcified as we are not advertising */
NimBLEDevice::init("");
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
*/
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison
/** 2 different ways to set security - both calls achieve the same result.
* no bonding, no man in the middle protection, secure connections.
*
* These are the default values, only shown here for demonstration.
*/
NimBLEDevice::setSecurityAuth(true, true, true);
NimBLEDevice::setSecurityAuth(BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM | BLE_SM_PAIR_AUTHREQ_SC);
/** Optional: set the transmit power, default is 3db */
#ifdef ESP_PLATFORM
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
#else
NimBLEDevice::setPower(9); /** +9db */
#endif
/** Optional: set any devices you don't want to get advertisments from */
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff"));
/** create new scan */
NimBLEScan* pScan = NimBLEDevice::getScan();
/** create a callback that gets called when advertisers are found */
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
/** Set scan interval (how often) and window (how long) in milliseconds */
pScan->setInterval(45);
pScan->setWindow(15);
/** Active scan will gather scan response data from advertisers
* but will use more energy from both devices
*/
pScan->setActiveScan(true);
/** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever
* Optional callback for when scanning stops.
*/
pScan->start(scanTime, scanEndedCB);
}
void loop (){
/** Loop here until we find a device we want to connect to */
while(!doConnect){
delay(1);
}
mqtt.loop();
doConnect = false;
/** Found a device we want to connect to, do it now */
if(connectToServer()) {
Serial.println("Success! we should now be getting notifications, scanning for more!");
} else {
Serial.println("Failed to connect, starting scan");
}
NimBLEDevice::getScan()->start(scanTime,scanEndedCB);
}
ca donne ca pour le moment