From 947686f7b1649ab53ee888552e2731687b5f99d1 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 28 Apr 2024 09:35:48 +0100 Subject: [PATCH] hq --- Buffer.h | 52 ++++++++++++++++++++++++ ESPBMS.ino | 37 +++++++---------- HQ.h | 98 ++++++++++++++++++++++++++++++++++++++++++++++ WebSocketManager.h | 83 --------------------------------------- victron.ino | 14 +++---- 5 files changed, 172 insertions(+), 112 deletions(-) create mode 100644 Buffer.h create mode 100644 HQ.h delete mode 100644 WebSocketManager.h diff --git a/Buffer.h b/Buffer.h new file mode 100644 index 0000000..99099db --- /dev/null +++ b/Buffer.h @@ -0,0 +1,52 @@ +#ifndef BUFFER_H +#define BUFFER_H + +#include + +class Buffer { +private: + char* data_; + size_t size_; + size_t currentLength_; + const char separator_; + boolean overflow=false; + +public: + Buffer(size_t size, const char separator = '\0') + : size_(size), currentLength_(0), separator_(separator) { + data_ = new char[size_]; + data_[0] = '\0'; // Ensure the buffer is null-terminated + } + + ~Buffer() { + delete[] data_; + } + + bool add(const char* str) { + size_t strLength = strlen(str); + if (currentLength_ + strLength + 1 + (currentLength_ > 0 && separator_ != '\0') < size_) { + if (currentLength_ > 0 && separator_ != '\0') { + strcat(data_, &separator_); + ++currentLength_; + } + strcat(data_, str); + currentLength_ += strLength; + return true; + } else { + overflow=true; + return false; + } + } + + void clear() { + data_[0] = '\0'; + currentLength_ = 0; + overflow=false; + } + + const char* get() const { + return data_; + } +}; + +#endif diff --git a/ESPBMS.ino b/ESPBMS.ino index 1112970..3f1b833 100644 --- a/ESPBMS.ino +++ b/ESPBMS.ino @@ -1,8 +1,6 @@ #include "BLEDevice.h" #include -#include "WebSocketManager.h" - -WebSocketManager wsManager("ws://chodbox.home.arpa", 8765, "/"); +#include "HQ.h" static BLEUUID serviceUUID("0000ff00-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms service static BLEUUID charUUID_rx("0000ff01-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms rx id @@ -34,7 +32,6 @@ void setup() { WiFi.onEvent(WiFiEvent); ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE); BLEDevice::init(""); - wsManager.begin(); } void loop() { @@ -53,11 +50,6 @@ void loop() { delay(250); } - while(!wsManager.isConnected()){ - Serial.println("Wait for socket..."); - delay(250); - } - for (int i = 0; i < foundDevices.getCount(); i++) { delay(1000); Serial.printf("\r\n\r\n===============================\r\n\r\n"); @@ -186,6 +178,7 @@ void loop() { } } pClient->disconnect(); + hq.poll(); } Serial.println("Reboot!"); delay(100); @@ -342,14 +335,14 @@ bool processBasicInfo(byte *data, unsigned int dataLen){ uint16_t BalanceCodeHigh = (two_ints_into16(data[14], data[15])); uint8_t MosfetStatus = ((byte)data[20]); - 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); + hq.send("test.RC.%s.Voltage %f",currentName, (float)Volts / 1000); + hq.send("test.RC.%s.Amps %f",currentName, (float)Amps / 1000); + hq.send("test.RC.%s.Watts %f",currentName, (float)Watts); + hq.send("test.RC.%s.Capacity_Remain_Ah %f",currentName, (float)CapacityRemainAh / 1000); + hq.send("test.RC.%s.Capacity_Remain_Wh %f",currentName, ((float)(CapacityRemainAh) / 1000) * ((float)(Volts) / 1000)); + hq.send("test.RC.%s.Capacity_Remain_Percent %d",currentName, CapacityRemainPercent); + hq.send("test.RC.%s.Temp1 %f",currentName, (float)Temp1 / 10); + hq.send("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); @@ -383,13 +376,13 @@ bool processCellInfo(byte *data, unsigned int dataLen) _cellMin = CellVolt; } - wsManager.sendText("test.RC.%s.Cell.%d.Voltage %f",currentName, i+1,(float)CellVolt/1000); + hq.send("test.RC.%s.Cell.%d.Voltage %f",currentName, i+1,(float)CellVolt/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); + hq.send("test.RC.%s.Max_Cell_Voltage %f",currentName, (float)_cellMax / 1000); + hq.send("test.RC.%s.Min_Cell_Voltage %f",currentName, (float)_cellMin / 1000); + hq.send("test.RC.%s.Difference_Cell_Voltage %f",currentName, (float)(_cellMax - _cellMin) / 1000); + hq.send("test.RC.%s.Average_Cell_Voltage %f",currentName, (float)(_cellSum / NumOfCells) / 1000); gotCellInfo=true; diff --git a/HQ.h b/HQ.h new file mode 100644 index 0000000..0949cc2 --- /dev/null +++ b/HQ.h @@ -0,0 +1,98 @@ +#ifndef HQ_H +#define HQ_H + +#include +#include +#include "Buffer.h" +#include "ca_cert.h" + +class HQ { +public: + // Public static function to get the instance of the singleton class + static HQ& getInstance() { + static HQ instance; // Create a single instance of the class on first call + return instance; // Return the single instance on each call + } + +private: + // Private constructor and copy constructor to prevent outside instantiation + HQ(){ + client = new WiFiClientSecure; + if(!client) { + Serial.printf("Unable to create HTTP client\r\n"); + } + client->setCACert(ca_cert); + client->setHandshakeTimeout(5); + } + HQ(const HQ&) = delete; + Buffer txBuffer=Buffer(4096,'&'); + Buffer rxBuffer=Buffer(1024,'\n'); + WiFiClientSecure *client; + +public: + unsigned long httpErrors=0; + boolean send(const char *s){ + Serial.printf("HQ_SEND:%s\r\n",s); + return txBuffer.add(s); + } + template + boolean send(const char* format, T arg1, Args... args) + { + static char msg[1024]; + snprintf(msg, 1024, format, arg1, args...); + + return send(msg); + } + + boolean poll(){ + String payload; + if(strlen(txBuffer.get())){ + payload+=txBuffer.get(); + } + if(payload.isEmpty()){ + return true; + } + HTTPClient https; + https.setTimeout(1000); + https.setConnectTimeout(1000); + https.addHeader("Content-Type","application/x-www-form-urlencoded"); + String url="https://api.ecomotus.co.uk/api/v1/graphite"; + Serial.printf("Connecting to %s\r\n",url.c_str()); + if(!https.begin(*client, url)) { // HTTPS + Serial.printf("HTTP Connection Failed\r\n"); + httpErrors++; + return false; + } + int httpCode=https.POST(payload); + if(httpCode==200){ + txBuffer.clear(); + // Read all the lines of the reply from server and print them to Serial + boolean command=false; + char buff[128]; + int totalSize=0; + WiFiClient * stream = https.getStreamPtr(); + while(stream->available() && totalSize<1000) { + size_t size=stream->readBytesUntil('\n',buff,120); + totalSize+=size; + buff[size]=0; + Serial.printf("Response: %s\r\n",buff); + if(command==true){ + rxBuffer.add(buff); + command=false; + } + if(0==strcmp(buff,"COMMAND")){ + command=true; + } + } + Serial.printf("Got %d bytes\r\n",totalSize); + }else{ + Serial.printf("HTTP Error: %d\r\n",httpCode); + httpErrors++; + return false; + } + return true; + } +}; + +HQ& hq = HQ::getInstance(); +#endif diff --git a/WebSocketManager.h b/WebSocketManager.h deleted file mode 100644 index a6bde96..0000000 --- a/WebSocketManager.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef WEBSOCKETMANAGER_H -#define WEBSOCKETMANAGER_H - -#include -#include -#include -#include "ca_cert.h" - -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() && 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); - } - } - - static bool isConnected() { - return connected; - } - -private: - static void webSocketTask(void *param) { - WiFiClient client; - //client.setCACert(ca_cert); - //webSocket.beginSSL(serverUrl.c_str(), serverPort, serverPath.c_str(), ca_cert); - webSocket.begin(serverUrl.c_str(), serverPort, serverPath.c_str()); - webSocket.onEvent(webSocketEvent); - webSocket.setReconnectInterval(1000); - - 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: - connected = false; - Serial.println("[WebSocket] Disconnected"); - break; - case WStype_CONNECTED: - connected = true; - 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; - static bool connected; -}; - -// Define static members -WebSocketsClient WebSocketManager::webSocket; -String WebSocketManager::serverUrl = ""; -uint16_t WebSocketManager::serverPort = 0; -String WebSocketManager::serverPath = ""; -bool WebSocketManager::connected = false; - -#endif // WEBSOCKETMANAGER_H diff --git a/victron.ino b/victron.ino index c477990..8c5e78e 100644 --- a/victron.ino +++ b/victron.ino @@ -185,12 +185,12 @@ void decodeVictron(BLEAdvertisedDevice advertisedDevice) { return; } - 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); + hq.send("test.RC.MPPT.1.Battery_Volts %f",batteryVoltage); + hq.send("test.RC.MPPT.1.Battery_Amps %f",batteryCurrent); + hq.send("test.RC.MPPT.1.Battery_Watts %f",batteryVoltage*batteryCurrent); + hq.send("test.RC.MPPT.1.Solar_Watts %f",inputPower); + hq.send("test.RC.MPPT.1.Output_Current %f",outputCurrent); + hq.send("test.RC.MPPT.1.Yield %f",todayYield); + hq.send("test.RC.MPPT.1.State %d",deviceState); } }