#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#define MAXWAIT 500 //Max time to wait for response between messages
#define MAXMESSAGELEN 60 //Maxiumum message length
const char *ssid = "SBX";
const char *password = "leftturn";
const int redButtonPin = 12; // Red button connected to D12
const int greenButtonPin = 33; // Green button connected to D33
const int blueButtonPin = 32; // Blue button connected to D32
const int redLEDPin = 27; // Red LED pin connected to D27
const int greenLEDPin = 26; // Green LED pin connected to D26
const int blueLEDPin = 25; // Blue LED pin connected to D25
// Sensor data structure
struct ModBusRequest {
char operation[40];
int PDU;
int address;
int hex;
int length;
bool negative;
bool datamode;
bool datatype;
int scale;
char unit[3];
};
struct modbusData {
uint8_t msgLength; // Message length
uint8_t data[MAXMESSAGELEN]; // The data
char error[40]; //Error message for result - eg CRC error
};
// Array to hold all instances of ModBusRequest
ModBusRequest ModBusRequestArray[] = {
{"Time Year ", 4, 33022, 0x80FE, 1, false, false, true, 1, ""},
{"Time Month", 4, 33023, 0x80FF, 1, false, false, true, 1, ""},
{"Time Day ", 4, 33024, 0x8100, 1, false, false, true, 1, ""},
{"Time Hour ", 4, 33025, 0x8101, 1, false, false, true, 1, ""},
{"Time Min ", 4, 33026, 0x8102, 1, false, false, true, 1, ""},
{"Time Sec ", 4, 33027, 0x8103, 1, false, false, true, 1, ""},
{"Product Mode", 4, 33000, 0x80E8, 12, false, false, true, 1, ""},
{"Solar Power", 4, 33057, 0x8121, 2, false, false, true, 1, "W"},
{"Inverter Power", 4, 33151, 0x817F, 2, true, false, true, 1, "W"},
{"Active Power", 4, 33079, 0x8137, 2, true, false, true, 1, "W"},
{"Meter Power ", 4, 33130, 0x816A, 2, true, false, true, 1, "W"},
{"House Power", 4, 33147, 0x817B, 1, false, false, true, 1, "W"},
{"Battery Power", 4, 33149, 0x817D, 2, true, false, true, 1, "W"},
{"Batt Dirn (OUT = 1) ", 4, 33135, 0x816F, 1, false, false, true, 1, ""},
{"Battery Charge Value", 4, 33139, 0x8173, 1, false, false, true, 1, "%"},
{"Battery Health Value", 4, 33140, 0x8174, 1, false, false, true, 1, "%"},
{"Inverter Temperature", 4, 33093, 0x8145, 1, true, false, true, 10, "C"}
};
ModBusRequest opTest [] = {
{"Just Testing ", 4, 33022, 0x80FE, 1, false, false, true, 1, "X"}
};
#include "form.h"
modbusData outmsg;
modbusData results[20] ;
int swapBytes(int value) {
// Use bitwise operations to swap the bytes
value = ((value >> 8) & 0xFF) | ((value << 8) & 0xFF00);
return value;
}
String byteArrayToHexString(byte* b, size_t blen) {
String result = "";
for (size_t i = 0; i < blen; i++) {
// Convert each byte to a two-digit hex string
char hexString[4];
sprintf(hexString, " %02X", b[i]);
// Concatenate the hex string to the result
result += hexString;
}
return result;
}
// Function to calculate Modbus RTU CRC
uint16_t calculateModbusCRC(const char* data, int len) {
uint16_t crc = 0xFFFF; // Initial value
for (int i = 0; i < len; i++) {
crc ^= static_cast<uint8_t>(data[i]); // XOR with current byte
for (int j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001; // Right shift and XOR with polynomial
} else {
crc = crc >> 1; // Right shift
}
}
}
return crc;
}
// Function to calculate Modbus RTU CRC
uint16_t calculateModbusCRC(const byte* data, int len) {
uint16_t crc = 0xFFFF; // Initial value
for (int i = 0; i < len; i++) {
//Serial.println(data[i],HEX);
crc ^= static_cast<uint8_t>(data[i]); // XOR with current byte
for (int j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001; // Right shift and XOR with polynomial
} else {
crc = crc >> 1; // Right shift
}
}
}
return crc;
}
void makeMsg(const ModBusRequest& sd, modbusData& msg) {
msg.data[0] = 0x1;
msg.data[1] = sd.PDU;
msg.data[2] = sd.hex >> 8;
msg.data[3] = sd.hex & 0xff;
msg.data[4] = 0;
msg.data[5] = sd.length;
//Now need to get the checksum
msg.msgLength = 8 ; //Includes checksum
int crc = calculateModbusCRC((const char*) msg.data, msg.msgLength - 2);
msg.data[6] = crc & 0xff;
msg.data[7] = crc >> 8;
}
void listMsg(modbusData msg) {
for (int j = 0; j < msg.msgLength; ++j) {
if (msg.data[j] < 16 ) {
Serial.print("0");
}
Serial.print(msg.data[j], HEX);
Serial.print(" ");
}
Serial.println("");
}
// Function to send Modbus RTU queries
void sendModbusQueries( ModBusRequest ModBusRequestArray[], size_t arraySize) {
Serial.print( "Processing "); Serial.print( arraySize); Serial.println( "Requests. ");
for (size_t i = 0; i < arraySize; ++i) {
delay(20);
//3. Red light on start of each sub-requests
digitalWrite(redLEDPin, HIGH);
digitalWrite(blueLEDPin, LOW);
makeMsg(ModBusRequestArray[i], outmsg);
Serial.print("Query for ");
Serial.print(ModBusRequestArray[i].operation);
Serial.println(": ");
listMsg(outmsg);
Serial2.write(outmsg.data, outmsg.msgLength);
//============================
// Check if there is data available on Serial2
long timeToRespond = millis();
//Allow some time for response
while (Serial2.available() == 0) {
if (millis() - timeToRespond > MAXWAIT) {
Serial.println("No reply.");
break;
}
delay(2);
}
timeToRespond = millis() - timeToRespond ;
// Read incoming data while available
int index = 0;
while (Serial2.available() > 0) {
byte rx = Serial2.read();
results[i].data[index++] = rx;
Serial.print(" RX =>"); Serial.println(rx, HEX);
// Check for buffer overflow
if (index >= MAXMESSAGELEN) {
break;
}
}
// Store the length of the result
results[i].msgLength = static_cast<uint8_t>(index);
if (index == 0 ) { //No data received
//Create dummy test data
results[i].data[0] = 0x01;
results[i].data[1] = 0x04;
int len = ModBusRequestArray[i].length * 2;
results[i].data[2] = len;
int z = 0;
for (z = 3; z < len + 3; z += 2) {
//Create dummy result
if (len == 4 && z < 5 ) {
results[i].data[z] = 0;
} else {
results[i].data[z] = 0;
results[i].data[z + 1] = z + i;
}
}
results[i].msgLength = len + 5;
int crc = calculateModbusCRC((const char*) results[i].data, results[i].msgLength - 2);
results[i].data[3 + len] = crc & 0xff;
results[i].data[4 + len ] = crc >> 8;
} else {
//Data was received
digitalWrite(blueLEDPin, HIGH);
}
//Calculate checksum of response
int calcCRC= calculateModbusCRC((const char*) results[i].data, results[i].msgLength - 2);
int crcLocn = results[i].msgLength - 2;
int inCRC = results[i].data[crcLocn +1 ] << 8 + results[i].data[crcLocn];
if (inCRC != calcCRC){
Serial.println("CRC Mismatch. ");
Serial.print("Recvd:");Serial.print(inCRC,HEX);
Serial.print("Calc :");Serial.println(calcCRC,HEX);
strcpy(results[i].error, "CRC error");
//Add data to the message structure
} else {
Serial.println("CRC OK ");
strcpy(results[i].error, "");
}
Serial.print("Result Length: ");
Serial.print(results[i].msgLength);
Serial.print(" Result: ");
listMsg(results[i]);
digitalWrite(redLEDPin, LOW);
}
} //end sendModbusQueries
// Function to decode the response data
String decodeResponse(uint8_t *responseData, int dataLength, int scale) {
String decodedResult = "";
int rlen = responseData[2];
if (rlen>4){ //Just return hex data values
String hexString = ""; // Clear the output hex string
// Loop through each character in the input string
for (int i = 0; i < rlen; ++i) {
// Convert the current character to its hexadecimal representation
char hexBuffer[4];
snprintf(hexBuffer, sizeof(hexBuffer), " %02X", static_cast<unsigned char>(responseData[i]));
// Append the hexadecimal representation to the output hex string
hexString += hexBuffer;
}
return hexString;
}
for (int i = 0; i < rlen; i += 2) {
// Combine two bytes into a one
// Byte order H,L
long value = (responseData[i + 3] << 8) + responseData[i + 4] ;
if (rlen == 4 ) {
value += (responseData[i + 5] << 8) + responseData[i + 6] + (value << 16) ;
i += 2; //double increment i
}
//Some items are scaled like temperature - correct scaling now
if (scale != 1) {
float avalue = (0.0 + value) / scale;
decodedResult += String(avalue);
} else {
// Convert the integer to a string and append to the result
decodedResult += String(value);
}
// If there are more pairs, separate them by commas
if (i + 2 < responseData[2]) {
decodedResult += ", ";
}
//Serial.println(decodedResult);
}
return decodedResult;
}
String makeHTML() {
// Construct HTML table
String htmlTable = "<table border='1'>\n<tr><th>Operation</th><th>Data</th><th>Length</th></tr>";
for (int i = 0; i < sizeof(ModBusRequestArray) / sizeof(ModBusRequestArray[0]); i++) {
// Assuming results[i].data contains the response data
int totalLength = results[i].msgLength;
int responseDataLength = results[i].data[2]; // Response data length
int scale = ModBusRequestArray[i].scale;
// Decode response data
String decodedData = decodeResponse(results[i].data, responseDataLength,scale);
htmlTable += "\n<tr><td>" + String(ModBusRequestArray[i].operation) + \
"</td><td>" + decodedData + String(ModBusRequestArray[i].unit) + \
"</td><td>"+String(totalLength) +" " + String(results[i].error) +"</td></tr>";
}
htmlTable += "\n</table>";
// Print the HTML table to Serial
Serial.println(htmlTable);
// You can also send this HTML table to a web server or display it on a web page, depending on your application.
return htmlTable;
}
WebServer server(80);
const int led = 2;
//Convert String parameter to Int
int toInt(String x){
return x.toInt();
}
void TXtest (){
Serial.println("\nRunning TXtest");
String message = R"XX(<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solis Info</title>
<style>
body { background-color: #ffffff; font-family: Arial, Helvetica, Sans-Serif;}
</style>
<H1>Solis Test </H1>
)XX";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n<P>";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
message += "\n\n<P>";
/*
// Sensor data structure
struct ModBusRequest {
char operation[40];
int PDU;
int address;
int hex;
int length;
bool negative;
bool datamode;
bool datatype;
int scale;
char unit[3];
};
ModBusRequest opTest [] = {
{"Just Testing ", 4, 33022, 0x80FE, 1, false, false, true, 1, "X"}
};
URI: /test
Method: POST
Arguments: 4
0 name: check
1 prefix: 02
2 number: 12345
3 size: 2
*/
//Build up the values in a Simple String
byte b[8];
String temp;
b[0] = 0x1; //Client address
b[1] = toInt(server.arg(1)); //Modbus request type
int number = toInt(server.arg(2)); //Number of the request (entered in decimal)
b[2] = number >> 8; //High byte
b[3] = number & 0xff; //low byte
b[4] = 0; //Upper length indicator - always 0
b[5] = toInt(server.arg(3)); //Expected Number of words in response Usually 1 or 2
// Calculate check sum on b[0] to b[5]
int CRC = calculateModbusCRC(b, 6);
b[6] = CRC & 0xff;
b[7] = CRC >> 8;
String hexString= byteArrayToHexString(b,8);
Serial.print(hexString);
message += "Sending: " + hexString;
server.send(200, "text/html", message);
return;
//Now create a request based on the input with an added checksum
Serial.print ("\n\nCreating message:"); Serial.println (server.arg(0));
Serial.print ("Hex:"); Serial.println(server.arg(1));
String myhtml= "<h1> "+ server.arg(0) + " " + server.arg(1) + "<h1><P>\n";
/*
char operation[40];
int PDU;
int address;
int hex;
*/
//Build up request
digitalWrite(greenLEDPin, LOW);
//Create response table
String table = makeHTML();
//return response
String out = R"XX(<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="10" >
<title>Solis Info</title>
<style>
body { background-color: #ffffff; font-family: Arial, Helvetica, Sans-Serif;}
/* Style for the table */
table {
border-collapse: collapse;
}
/* Style for the table header (first row) */
table th {
background-color: #4CAF50; /* Green color for the header row */
color: white;
padding: 12px;
text-align: left;
}
/* Style for alternating rows */
table tr:nth-child(even) {
background-color: #f1f1f1; /* Light green color for even rows */
}
table tr:nth-child(odd) {
background-color: white; /* White color for odd rows */
}
/* Style for table cells */
table td {
padding: 8px;
border: 1px solid #ddd;
}
</style>
</head>
<body>
<h1>Solis Info</h1>
)XX";
out += table;
out += "<P></body>";
server.send(200, "text/html", out);
}
void handleRoot() {
info();
}
void showForm(){
Serial.println("======= Test form display ==========");
digitalWrite(led, 1);
/*
const char * myhtml = R"XX(<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solis Test</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 50;
padding: 50;
height: 100vh;
}
form {
background-color: #fff;
padding: 40px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 400px;
width: 100%;
}
label {
display: block;
margin-bottom: 8px;
}
input {
width: 100%;
padding: 8px;
margin-bottom: 16px;
box-sizing: border-box;
}
button {
padding: 30px;
background-color: #4caf50;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
button.cancel {
background-color: #f44336;
}
</style>
</head>
<body>
<h1>Solis Test</h1>
<form action="/TXtest" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<label for="hexdata">Hex Data:</label>
<input type="text" id="hexdata" name="hexdata" required>
<button type="submit">Submit</button>
<button type="button" class="cancel">Cancel</button>
</form>
</body></html>)XX";
*/
server.send(200, "text/html", myhtml);
digitalWrite(led, 0);
}
void showParams() {
digitalWrite(led, 1);
String message = "<h2>Parameters </h2><P>";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
Serial.print(message);
digitalWrite(led, 0);
}
void listParameters(String message) {
digitalWrite(led, 1);
message += "\n\nURI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
Serial.print(message);
//server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void setup(void) {
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
Serial.begin(115200);
Serial2.begin(9600);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
pinMode(redButtonPin, INPUT_PULLUP);
pinMode(greenButtonPin, INPUT_PULLUP);
pinMode(blueButtonPin, INPUT_PULLUP);
pinMode(redLEDPin, OUTPUT);
pinMode(greenLEDPin, OUTPUT);
pinMode(blueLEDPin, OUTPUT);
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
digitalWrite(led, HIGH);
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Started Serial2 ");
/*
if (MDNS.begin("esp32")) {
Serial.println("MDNS responder started");
}
*/
server.on("/", handleRoot);
//server.on("/test.svg", drawGraph);
server.on("/inline", []() {
server.send(200, "text/plain", "this works as well");
});
server.on("/info", info);
server.on("/m1", sendM1);
server.on("/check", sendText);
server.on("/test", showForm);
server.on("/TXtest", TXtest);
server.onNotFound(showParams);
server.begin();
Serial.println("HTTP server started");
Serial2.begin(9600); // Initialize Serial2 at 9600 baud
}
void checkButtons() {
if (digitalRead(redButtonPin) == LOW) {
funcRed();
} else if (digitalRead(greenButtonPin) == LOW) {
funcGreen();
} else if (digitalRead(blueButtonPin) == LOW) {
funcBlue();
};
}
void funcRed() {
digitalWrite(redLEDPin, HIGH);
digitalWrite(greenLEDPin, LOW);
digitalWrite(blueLEDPin, LOW);
Serial.println("Red.");
delay(500);
}
void funcBlue() {
digitalWrite(blueLEDPin, HIGH);
digitalWrite(greenLEDPin, LOW);
digitalWrite(redLEDPin, LOW);
Serial.println("Blue.");
delay(500);
}
void funcGreen() {
digitalWrite(greenLEDPin, HIGH);
digitalWrite(redLEDPin, LOW);
digitalWrite(blueLEDPin, LOW);
Serial.println("Green.");
delay(500);
}
void loop(void) {
server.handleClient();
// Call the checkButtons function in the loop
checkButtons();
delay(2);//allow the cpu to switch to other tasks
}
void sendMessage(String parm) {
digitalWrite(redLEDPin, HIGH);
digitalWrite(greenLEDPin, LOW);
digitalWrite(blueLEDPin, LOW);
digitalWrite(led, LOW);
String out = "";
Serial.println("Input " + parm);
// Prepare the character array (the buffer)
int plen = parm.length();
Serial.print("Parameter length "); Serial.println(plen);
char char_array[plen + 1];
// Copy it over
parm.toCharArray(char_array, plen + 1);
// char_array is a char * array that contains HEX chars eg 010434... without the CRC data (low, high)
int bytelen = (plen + 1) / 2 + 2 ;
byte outData[bytelen + 1];
Serial.print("Byte array length "); Serial.println(bytelen);
outData[bytelen + 1] = 0; //ALlow use as char string
unHex(char_array, outData, plen);
//outData biw contains the binary data as an array of bytes
uint16_t CRC = calculateModbusCRC(outData, bytelen - 2); //Ignore the space for the CRC
//Insert the CRC data into the byte array
outData[bytelen - 2] = CRC & 0xFF;
outData[bytelen - 1] = (CRC >> 8) & 0xFF;
//Now get a string showing the hex using printf
//and output to client and log
Serial.print("Char * CRC: "); Serial.println(CRC, HEX);
sendToSerial(outData, bytelen);
//Only one message allowed - this is not shown
//server.send(200, "text/html", "Message sent<P>");
//Only one message allowed - this is not shown
//server.send(200, "text/html", "Sending Message to Serial 2<P>");
//out = out + "<h2>Outgoing message '" + server.arg(0) + "' Millis: " + String(millis()) + "</h2> <p>";
long responseTime = checkSerial2(out);
String hexOutput = "";
// Call the function to convert the string to hex
stringToHex(out, hexOutput);
out = R"XX(<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RS485 Demo</title>
<style>
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }
</style>
</head>
<body>
<h1>RS485 Response</h1>
)XX";
out += hexOutput;
out += "<P>Took: " + String(responseTime) + " mSec </body>";
server.send(200, "text/html", out);
digitalWrite(led, LOW);
digitalWrite(redLEDPin, LOW);
digitalWrite(greenLEDPin, LOW);
digitalWrite(blueLEDPin, LOW);
}
void sendText() {
listParameters("=== sendText ===");
sendMessage(server.arg(0)); //Pass a String variable containing HEX chars eg 010434... without the CRC data (low, high)
}
void sendM1() {
String param = "010480E8000C";
sendMessage(param);
}
void info() {
//1. Turn on Green LED
digitalWrite(greenLEDPin, HIGH);
//2. Start sending requests
sendModbusQueries(ModBusRequestArray, sizeof(ModBusRequestArray) / sizeof(ModBusRequestArray[0]));
//3. Turn off Green light when all requests processed.
digitalWrite(greenLEDPin, LOW);
//Create response table
String table = makeHTML();
//return response
String out = R"XX(<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="10" >
<title>Solis Info</title>
<style>
body {
background-color: #ffffff;
font-family: Arial, Helvetica, Sans-Serif;
}
button {
padding: 30px;
background-color: #4caf50;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* Style for the table */
table {
border-collapse: collapse;
}
/* Style for the table header (first row) */
table th {
background-color: #4CAF50; /* Green color for the header row */
color: white;
padding: 12px;
text-align: left;
}
/* Style for alternating rows */
table tr:nth-child(even) {
background-color: #f1f1f1; /* Light green color for even rows */
}
table tr:nth-child(odd) {
background-color: white; /* White color for odd rows */
}
/* Style for table cells */
table td {
padding: 8px;
border: 1px solid #ddd;
}
</style>
</head>
<body>
<h1>Solis Info</h1>
)XX";
out += table;
String tail = R"ZZ(
<P>
<button onclick="location.href = '\';" >Refresh </button>
<button onclick="location.href = '\test';" >Test</button>
)ZZ";
out += tail;
server.send(200, "text/html", out );
}
long checkSerial2(String &receivedString) {
// Check if there is data available on Serial2
long timeToRespond = millis();
//Allow some time for response
while (Serial2.available() == 0) {
if (millis() - timeToRespond > MAXWAIT) {
receivedString += "0000";
Serial.println("No reply.");
return -1;
}
delay(1);
}
timeToRespond = millis() - timeToRespond ;
while (Serial2.available() > 0) {
// Read the incoming byte
char incomingByte = Serial2.read();
Serial.print(" RX =>"); Serial.println(incomingByte, HEX);
// Append the incoming byte to the receivedString
receivedString += incomingByte;
}
return timeToRespond;
}
void unHex(const char* inP, byte* outP, size_t len) {
for (; len > 1; len -= 2) {
byte val = asc2byte(*inP++) << 4;
*outP++ = val | asc2byte(*inP++);
}
}
byte asc2byte(char chr) {
byte rVal = 0;
//Serial.print("asc2Byte: ");Serial.print(chr);Serial.print(" => ");
if (isdigit(chr)) {
rVal = chr - '0';
} else if (chr >= 'A' && chr <= 'F') {
rVal = (byte) chr + 10 - 'A';
}
//Serial.println(rVal,HEX);
return rVal;
}
// Function to send byte array to Serial2
void sendToSerial(const byte* data, int len) {
// Send data bytes
for (int i = 0; i < len; i++) {
byte b = data[i];
Serial.print("TX =>");
Serial.println(b, HEX);
Serial2.write(b);
}
}
void test() {
// Example usage
// 01 04 80 E8 00 0C //Product Model returns Inverter ID (param 0C?)
//:01 04 80 E8 00 0C 59 FB
/*000218-Tx:01 04 80 E8 00 0C 59 FB
000219-Rx:01041800F8000C000E000146464646464646464646464646464600
Actual 0104183102003D0040000136303331303233323241313130303438D390
3 1 0 2 3 2 2 a 1 1 0 0 4 8
85 A4
//Set the flag (param 0A?)
000230-Tx:01 04 81 5B 00 0A 29 E2
000231-Rx:01 04 14 00 00 00 04 00 00 00 01 00 00 00 04 06 08 00 00 00 00 00 00 EE EB
//Total PV Energy
000242-Tx:01 04 81 05 00 0A 48 30
000243-Rx:01 04 14 00 00 00 71 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 71 21 EE
*/
const byte data[] = {0x01, 0x04, 0x80, 0xE8, 0x00, 0x0C};
//expected Checksum : 0x59, 0xFB
sendToSerial( data, 6 );
}
void stringToHex(const String &inString, String &hexString) {
hexString = ""; // Clear the output hex string
// Loop through each character in the input string
for (size_t i = 0; i < inString.length(); ++i) {
// Convert the current character to its hexadecimal representation
char hexBuffer[4];
snprintf(hexBuffer, sizeof(hexBuffer), " %02X", static_cast<unsigned char>(inString[i]));
// Append the hexadecimal representation to the output hex string
hexString += hexBuffer;
}
}