From b1be320655065386bb9662bbbce2c51ce5a2951b Mon Sep 17 00:00:00 2001 From: James Date: Sat, 27 Apr 2024 19:37:14 +0100 Subject: [PATCH] websockets --- ESPBMS.ino | 141 ++++++++++----------------------------------- WebSocketManager.h | 73 +++++++++++++++++++++++ victron.ino | 14 ++--- 3 files changed, 109 insertions(+), 119 deletions(-) create mode 100644 WebSocketManager.h diff --git a/ESPBMS.ino b/ESPBMS.ino index e366664..00b09bc 100644 --- a/ESPBMS.ino +++ b/ESPBMS.ino @@ -1,20 +1,20 @@ #include "BLEDevice.h" #include -#include -#include -#include -#include -#include "ca_cert.h" -#include "config.h" +#include "WebSocketManager.h" -// NTP Client setup -WiFiUDP ntpUDP; -NTPClient timeClient(ntpUDP, "pool.ntp.org"); +WebSocketManager wsManager("wss://hq.ecomotus.co.uk", 443, "/"); 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 +#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN // ETH_CLOCK_GPIO17_OUT +#define ETH_POWER_PIN 16 +#define ETH_TYPE ETH_PHY_LAN8720 +#define ETH_ADDR 1 +#define ETH_MDC_PIN 23 +#define ETH_MDIO_PIN 18 + typedef struct { byte start; @@ -28,31 +28,15 @@ bool gotBasicInfo; bool gotCellInfo; static bool eth_ready = false; -WiFiClientSecure client; -HTTPClient https; - void setup() { - Serial.begin(115200); - eth_begin(); - timeClient.begin(); - client.setCACert(ca_cert); - client.setHandshakeTimeout(5); esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); - BLEDevice::init(""); // Initialize BLE device -} - -bool client_connect(){ - //https.setTimeout(preferences.getInt("http_timeout")); - //https.setConnectTimeout(preferences.getInt("http_timeout")); - //https.addHeader("Content-Type","application/x-www-form-urlencoded"); - String url="URL"; - https.end(); - if(!https.begin(client, url)) { // HTTPS - Serial.println("connect fail"); - return false; - } - Serial.println("connect ok"); - return true; + Serial.begin(115200); + ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE); + WiFi.onEvent(WiFiEvent); + BLEDevice::init(""); + wsManager.begin(); + wsManager.sendText("hello"); + wsManager.sendText("Up: %lu ms", millis()); } void loop() { @@ -66,14 +50,6 @@ void loop() { Serial.println("Devices found: " + String(foundDevices.getCount())); - while(!eth_ready){ - Serial.println("Wait for eth..."); - delay(250); - } - timeClient.update(); - //testClient("www.google.com", 80); - client_connect(); - for (int i = 0; i < foundDevices.getCount(); i++) { delay(1000); Serial.printf("\r\n\r\n===============================\r\n\r\n"); @@ -81,8 +57,6 @@ void loop() { BLEAdvertisedDevice advertisedDevice = foundDevices.getDevice(i); Serial.println("\nFound Device: " + String(advertisedDevice.toString().c_str())); - client_connect(); - std::string targetAddress = "d0:65:de:e5:89:76"; if (advertisedDevice.getAddress().toString() == targetAddress) { Serial.println("Victron device found!"); @@ -360,14 +334,14 @@ bool processBasicInfo(byte *data, unsigned int dataLen){ uint16_t BalanceCodeHigh = (two_ints_into16(data[14], data[15])); uint8_t MosfetStatus = ((byte)data[20]); - eth_send("test.RC.%s.Voltage %f",currentName, (float)Volts / 1000); - eth_send("test.RC.%s.Amps %f",currentName, (float)Amps / 1000); - eth_send("test.RC.%s.Watts %f",currentName, (float)Watts); - eth_send("test.RC.%s.Capacity_Remain_Ah %f",currentName, (float)CapacityRemainAh / 1000); - eth_send("test.RC.%s.Capacity_Remain_Wh %f",currentName, ((float)(CapacityRemainAh) / 1000) * ((float)(Volts) / 1000)); - eth_send("test.RC.%s.Capacity_Remain_Percent %d",currentName, CapacityRemainPercent); - eth_send("test.RC.%s.Temp1 %f",currentName, (float)Temp1 / 10); - eth_send("test.RC.%s.Temp2 %f",currentName, (float)Temp2 / 10); + wsManager.sendText("test.RC.%s.Voltage %f",currentName, (float)Volts / 1000); + wsManager.sendText("test.RC.%s.Amps %f",currentName, (float)Amps / 1000); + wsManager.sendText("test.RC.%s.Watts %f",currentName, (float)Watts); + wsManager.sendText("test.RC.%s.Capacity_Remain_Ah %f",currentName, (float)CapacityRemainAh / 1000); + wsManager.sendText("test.RC.%s.Capacity_Remain_Wh %f",currentName, ((float)(CapacityRemainAh) / 1000) * ((float)(Volts) / 1000)); + wsManager.sendText("test.RC.%s.Capacity_Remain_Percent %d",currentName, CapacityRemainPercent); + wsManager.sendText("test.RC.%s.Temp1 %f",currentName, (float)Temp1 / 10); + wsManager.sendText("test.RC.%s.Temp2 %f",currentName, (float)Temp2 / 10); /* Serial.printf("%s Balance Code Low: 0x%x\r\n",currentName, BalanceCodeLow); Serial.printf("%s Balance Code High: 0x%x\r\n",currentName, BalanceCodeHigh); @@ -401,13 +375,13 @@ bool processCellInfo(byte *data, unsigned int dataLen) _cellMin = CellVolt; } - eth_send("test.RC.%s.Cell.%d.Voltage %f",currentName, i+1,(float)CellVolt/1000); + wsManager.sendText("test.RC.%s.Cell.%d.Voltage %f",currentName, i+1,(float)CellVolt/1000); } - eth_send("test.RC.%s.Max_Cell_Voltage %f",currentName, (float)_cellMax / 1000); - eth_send("test.RC.%s.Min_Cell_Voltage %f",currentName, (float)_cellMin / 1000); - eth_send("test.RC.%s.Difference_Cell_Voltage %f",currentName, (float)(_cellMax - _cellMin) / 1000); - eth_send("test.RC.%s.Average_Cell_Voltage %f",currentName, (float)(_cellSum / NumOfCells) / 1000); + wsManager.sendText("test.RC.%s.Max_Cell_Voltage %f",currentName, (float)_cellMax / 1000); + wsManager.sendText("test.RC.%s.Min_Cell_Voltage %f",currentName, (float)_cellMin / 1000); + wsManager.sendText("test.RC.%s.Difference_Cell_Voltage %f",currentName, (float)(_cellMax - _cellMin) / 1000); + wsManager.sendText("test.RC.%s.Average_Cell_Voltage %f",currentName, (float)(_cellSum / NumOfCells) / 1000); gotCellInfo=true; @@ -456,30 +430,6 @@ int16_t two_ints_into16(int highbyte, int lowbyte) // turns two bytes into a sin return result; } -///// - -/* - * ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator - * ETH_CLOCK_GPIO0_OUT - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720 - * ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720 - * ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720 -*/ -#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN // ETH_CLOCK_GPIO17_OUT - -// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source) -#define ETH_POWER_PIN 16 - -// Type of the Ethernet PHY (LAN8720 or TLK110) -#define ETH_TYPE ETH_PHY_LAN8720 - -// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110) -#define ETH_ADDR 1 - -// Pin# of the I²C clock signal for the Ethernet PHY -#define ETH_MDC_PIN 23 - -// Pin# of the I²C IO signal for the Ethernet PHY -#define ETH_MDIO_PIN 18 void WiFiEvent(WiFiEvent_t event) { Serial.print("E:"); @@ -518,36 +468,3 @@ void WiFiEvent(WiFiEvent_t event) { break; } } - -// Overloaded template function for formatted sending -template -void eth_send(const char* format, Args... args) { - constexpr std::size_t bufferSize = 1024; // Define a reasonable default buffer size - std::array buffer; - snprintf(buffer.data(), buffer.size(), format, args...); - eth_send(buffer.data()); // Call the original eth_send function -} - -void eth_send(const char *data) { - if(!https.connected()){ - https.end(); - client_connect(); - } - Serial.print("http connecting...\r\n"); - Serial.printf("ETH Send: %s\r\n", data); - int httpCode=https.POST(data); - if(httpCode==200){ - Serial.println("post ok"); - while (client.available()) { - Serial.write(client.read()); - } - }else{ - Serial.print("post fail:"); - Serial.println(httpCode); - } -} - -void eth_begin() { - WiFi.onEvent(WiFiEvent); - ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE); -} diff --git a/WebSocketManager.h b/WebSocketManager.h new file mode 100644 index 0000000..f6ea30d --- /dev/null +++ b/WebSocketManager.h @@ -0,0 +1,73 @@ +#ifndef WEBSOCKETMANAGER_H +#define WEBSOCKETMANAGER_H + +#include +#include +#include "ca_cert.h" // Include the CA certificate + +class WebSocketManager { +public: + WebSocketManager(const char* server, uint16_t port, const char* url) { + serverUrl = server; + serverPort = port; + serverPath = url; + } + + void begin() { + xTaskCreate(&WebSocketManager::webSocketTask, "WebSocketTask", 8192, nullptr, 1, nullptr); + } + + template + void sendText(const char* format, Args... args) { + if (webSocket.isConnected()) { + char buffer[512]; // Define a buffer to hold the constructed message + snprintf(buffer, sizeof(buffer), format, args...); // Use snprintf to format the string + webSocket.sendTXT(buffer); + } + } + +private: + static void webSocketTask(void *param) { + WiFiClientSecure client; + client.setCACert(ca_cert); + webSocket.beginSSL(serverUrl.c_str(), serverPort, serverPath.c_str(), ca_cert); + webSocket.onEvent(webSocketEvent); + webSocket.setReconnectInterval(5000); + + for (;;) { + webSocket.loop(); + vTaskDelay(1 / portTICK_PERIOD_MS); + } + } + + static void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { + switch (type) { + case WStype_DISCONNECTED: + Serial.println("[WebSocket] Disconnected"); + break; + case WStype_CONNECTED: + Serial.println("[WebSocket] Connected"); + break; + case WStype_TEXT: + Serial.print("[WebSocket] Received: "); + Serial.println((char*)payload); + break; + case WStype_BIN: + Serial.println("[WebSocket] Received binary data"); + break; + } + } + + static WebSocketsClient webSocket; + static String serverUrl; + static uint16_t serverPort; + static String serverPath; +}; + +// Define static members +WebSocketsClient WebSocketManager::webSocket; +String WebSocketManager::serverUrl = ""; +uint16_t WebSocketManager::serverPort = 0; +String WebSocketManager::serverPath = ""; + +#endif // WEBSOCKETMANAGER_H diff --git a/victron.ino b/victron.ino index 903eeb0..c477990 100644 --- a/victron.ino +++ b/victron.ino @@ -185,12 +185,12 @@ void decodeVictron(BLEAdvertisedDevice advertisedDevice) { return; } - eth_send("test.RC.MPPT.1.Battery_Volts %f",batteryVoltage); - eth_send("test.RC.MPPT.1.Battery_Amps %f",batteryCurrent); - eth_send("test.RC.MPPT.1.Battery_Watts %f",batteryVoltage*batteryCurrent); - eth_send("test.RC.MPPT.1.Solar_Watts %f",inputPower); - eth_send("test.RC.MPPT.1.Output_Current %f",outputCurrent); - eth_send("test.RC.MPPT.1.Yield %f",todayYield); - eth_send("test.RC.MPPT.1.State %d",deviceState); + wsManager.sendText("test.RC.MPPT.1.Battery_Volts %f",batteryVoltage); + wsManager.sendText("test.RC.MPPT.1.Battery_Amps %f",batteryCurrent); + wsManager.sendText("test.RC.MPPT.1.Battery_Watts %f",batteryVoltage*batteryCurrent); + wsManager.sendText("test.RC.MPPT.1.Solar_Watts %f",inputPower); + wsManager.sendText("test.RC.MPPT.1.Output_Current %f",outputCurrent); + wsManager.sendText("test.RC.MPPT.1.Yield %f",todayYield); + wsManager.sendText("test.RC.MPPT.1.State %d",deviceState); } }