/* * Xiaoxiang BMS to MQTT via WiFi * by Bas Vermulst - https://github.com/BeaverUI/ESP32-BluetoothBMS2MQTT * * Based on original work from https://github.com/kolins-cz/Smart-BMS-Bluetooth-ESP32/blob/master/README.md * === configuring === Using the #define parameters in the CONFIGURATION section, do the following: 1) configure WiFi via WIFI_SSID and WIFI_PASSWORD 2) configure MQTT broker via MQTTSERVER 3) set unique node name via NODE_NAME 4) ensure the BMS settings are OK. You can verify the name and address using the "BLE Scanner" app on an Android phone. === compiling === 1) Add ESP-WROVER to the board manager: - File --> Preferences, add to board manager URLs: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - Then, Tools --> Board --> Board manager... --> install ESP32 package v2.0.3 or later. 2) Install required libraries: - MQTT (by Joel Gaehwiler) Install via "Manage Libraries..." under Tools. 3) Configure board: Select Tools --> Board --> "ESP32 Arduino" --> "ESP WRover module" 4) Connect board via USB. 5) Configure programming options: Select appropriate programming port under Tools --> Port Select correct partitioning: 1.9MB app (with OTA) or 2MB app with 2 MB SPIFFS - otherwise it won't fit 6) Program and go! */ // ==== CONFIGURATION ==== // BMS #define BMS_MAX_CELLS 15 // defines size of data types #define BMS_POLLING_INTERVAL 10*60*1000 // data output interval (shorter = connect more often = more battery consumption from BMS) in ms // BLE #define BLE_NAME "BMS 1.1" // name of BMS #define BLE_SCAN_DURATION 1 // duration of scan in seconds #define BLE_REQUEST_DELAY 500 // package request delay after connecting - make this large enough to have the connection established in ms #define BLE_TIMEOUT 60*1000 // timeout of scan + gathering packets (too short will fail collecting all packets) in ms #define BLE_CALLBACK_DEBUG true // send debug messages via MQTT & serial in callbacks (handy for finding your BMS address, name, RSSI, etc) // ==== MAIN CODE ==== #include "datatypes.h" // for brevity the BMS stuff is in this file #include // for BLE #include // to read ESP battery voltage #include // to get reset reason // Init BMS static BLEUUID serviceUUID("0000ff00-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms service static BLEUUID charUUID_rx("0000ff01-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms rx id static BLEUUID charUUID_tx("0000ff02-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms tx id const byte cBasicInfo = 3; //datablock 3=basic info const byte cCellInfo = 4; //datablock 4=individual cell info packBasicInfoStruct packBasicInfo; packCellInfoStruct packCellInfo; unsigned long bms_last_update_time=0; bool bms_status; #define BLE_PACKETSRECEIVED_BEFORE_STANDBY 0b11 // packets to gather before disconnecting // Other stuff float battery_voltage=0; // internal battery voltage String debug_log_string=""; hw_timer_t * wd_timer = NULL; void debug(String s){ Serial.println(s); } void setup(){ Serial.begin(115200); } // === Main stuff ==== void loop(){ bleGatherPackets(); } /* mqttclient.publish(GetTopic("ip"), IPAddressString(WiFi.localIP())); mqttclient.publish(GetTopic("free-heap"), String(ESP.getFreeHeap())); mqttclient.publish(GetTopic("maxalloc-heap"), String(xPortGetMinimumEverFreeHeapSize())); mqttclient.publish(GetTopic("ssid"), WiFi.SSID()); mqttclient.publish(GetTopic("rssi"), String(WiFi.RSSI())); mqttclient.publish(GetTopic("reset-reason"), String(GetResetReason(0)) + String(" | ") + String(GetResetReason(1))); mqttclient.publish(GetTopic("runtime"), String(millis()/1000)); mqttclient.publish(GetTopic("battery-voltage"), String(battery_voltage,2)); mqttclient.publish(GetTopic("bms-status"), String(bms_status)); mqttclient.publish(GetTopic("bms-status-age"), String( (millis()-bms_last_update_time)/1000 )); if(bms_status){ mqttclient.publish(GetTopic("number-of-cells"), String(packCellInfo.NumOfCells)); mqttclient.publish(GetTopic("current"), String((float)packBasicInfo.Amps / 1000,2)); mqttclient.publish(GetTopic("voltage"), String((float)packBasicInfo.Volts / 1000,2)); if(packCellInfo.NumOfCells != 0){ mqttclient.publish(GetTopic("cell-voltage"), String((float)packBasicInfo.Volts /(1000*packCellInfo.NumOfCells), 2)); } mqttclient.publish(GetTopic("cell-diff"), String((float)packCellInfo.CellDiff, 0)); mqttclient.publish(GetTopic("soc"), String((float)packBasicInfo.CapacityRemainPercent,1)); mqttclient.publish(GetTopic("temperature-1"), String((float)packBasicInfo.Temp1 / 10,1)); mqttclient.publish(GetTopic("temperature-2"), String((float)packBasicInfo.Temp2 / 10,1)); } MqttPublishDebug(); mqttclient.loop(); } */