This commit is contained in:
James 2024-04-28 09:35:48 +01:00
parent 49f4c9ab34
commit 947686f7b1
5 changed files with 172 additions and 112 deletions

52
Buffer.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef BUFFER_H
#define BUFFER_H
#include <cstring>
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

View File

@ -1,8 +1,6 @@
#include "BLEDevice.h" #include "BLEDevice.h"
#include <ETH.h> #include <ETH.h>
#include "WebSocketManager.h" #include "HQ.h"
WebSocketManager wsManager("ws://chodbox.home.arpa", 8765, "/");
static BLEUUID serviceUUID("0000ff00-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms service 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_rx("0000ff01-0000-1000-8000-00805f9b34fb"); //xiaoxiang bms rx id
@ -34,7 +32,6 @@ void setup() {
WiFi.onEvent(WiFiEvent); WiFi.onEvent(WiFiEvent);
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE); ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE);
BLEDevice::init(""); BLEDevice::init("");
wsManager.begin();
} }
void loop() { void loop() {
@ -53,11 +50,6 @@ void loop() {
delay(250); delay(250);
} }
while(!wsManager.isConnected()){
Serial.println("Wait for socket...");
delay(250);
}
for (int i = 0; i < foundDevices.getCount(); i++) { for (int i = 0; i < foundDevices.getCount(); i++) {
delay(1000); delay(1000);
Serial.printf("\r\n\r\n===============================\r\n\r\n"); Serial.printf("\r\n\r\n===============================\r\n\r\n");
@ -186,6 +178,7 @@ void loop() {
} }
} }
pClient->disconnect(); pClient->disconnect();
hq.poll();
} }
Serial.println("Reboot!"); Serial.println("Reboot!");
delay(100); delay(100);
@ -342,14 +335,14 @@ bool processBasicInfo(byte *data, unsigned int dataLen){
uint16_t BalanceCodeHigh = (two_ints_into16(data[14], data[15])); uint16_t BalanceCodeHigh = (two_ints_into16(data[14], data[15]));
uint8_t MosfetStatus = ((byte)data[20]); uint8_t MosfetStatus = ((byte)data[20]);
wsManager.sendText("test.RC.%s.Voltage %f",currentName, (float)Volts / 1000); hq.send("test.RC.%s.Voltage %f",currentName, (float)Volts / 1000);
wsManager.sendText("test.RC.%s.Amps %f",currentName, (float)Amps / 1000); hq.send("test.RC.%s.Amps %f",currentName, (float)Amps / 1000);
wsManager.sendText("test.RC.%s.Watts %f",currentName, (float)Watts); hq.send("test.RC.%s.Watts %f",currentName, (float)Watts);
wsManager.sendText("test.RC.%s.Capacity_Remain_Ah %f",currentName, (float)CapacityRemainAh / 1000); hq.send("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)); hq.send("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); hq.send("test.RC.%s.Capacity_Remain_Percent %d",currentName, CapacityRemainPercent);
wsManager.sendText("test.RC.%s.Temp1 %f",currentName, (float)Temp1 / 10); hq.send("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.Temp2 %f",currentName, (float)Temp2 / 10);
/* /*
Serial.printf("%s Balance Code Low: 0x%x\r\n",currentName, BalanceCodeLow); Serial.printf("%s Balance Code Low: 0x%x\r\n",currentName, BalanceCodeLow);
Serial.printf("%s Balance Code High: 0x%x\r\n",currentName, BalanceCodeHigh); 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; _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); hq.send("test.RC.%s.Max_Cell_Voltage %f",currentName, (float)_cellMax / 1000);
wsManager.sendText("test.RC.%s.Min_Cell_Voltage %f",currentName, (float)_cellMin / 1000); hq.send("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); hq.send("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.Average_Cell_Voltage %f",currentName, (float)(_cellSum / NumOfCells) / 1000);
gotCellInfo=true; gotCellInfo=true;

98
HQ.h Normal file
View File

@ -0,0 +1,98 @@
#ifndef HQ_H
#define HQ_H
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#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<typename T, typename... Args>
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

View File

@ -1,83 +0,0 @@
#ifndef WEBSOCKETMANAGER_H
#define WEBSOCKETMANAGER_H
#include <WebSocketsClient.h>
#include <WiFiClientSecure.h>
#include <WiFiClient.h>
#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<typename... Args>
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

View File

@ -185,12 +185,12 @@ void decodeVictron(BLEAdvertisedDevice advertisedDevice) {
return; return;
} }
wsManager.sendText("test.RC.MPPT.1.Battery_Volts %f",batteryVoltage); hq.send("test.RC.MPPT.1.Battery_Volts %f",batteryVoltage);
wsManager.sendText("test.RC.MPPT.1.Battery_Amps %f",batteryCurrent); hq.send("test.RC.MPPT.1.Battery_Amps %f",batteryCurrent);
wsManager.sendText("test.RC.MPPT.1.Battery_Watts %f",batteryVoltage*batteryCurrent); hq.send("test.RC.MPPT.1.Battery_Watts %f",batteryVoltage*batteryCurrent);
wsManager.sendText("test.RC.MPPT.1.Solar_Watts %f",inputPower); hq.send("test.RC.MPPT.1.Solar_Watts %f",inputPower);
wsManager.sendText("test.RC.MPPT.1.Output_Current %f",outputCurrent); hq.send("test.RC.MPPT.1.Output_Current %f",outputCurrent);
wsManager.sendText("test.RC.MPPT.1.Yield %f",todayYield); hq.send("test.RC.MPPT.1.Yield %f",todayYield);
wsManager.sendText("test.RC.MPPT.1.State %d",deviceState); hq.send("test.RC.MPPT.1.State %d",deviceState);
} }
} }