Modbus TCP auslesen anstelle von lesen von UDP Daten

Hallo Community,

ich bin auf der Suche nach Hilfe für eine umprogrammierung eines bestehend stkech.

In dem aktuellen sketch werden hier Daten von einem Wechselrichter via UDP Protokoll gelesen . Dies würde ich gerne abändern das die Daten via Modbus TCP ausgelesen werden .

Also die Daten nicht einfach nur "abgehört/mitgelesen" werden wie bei UDP vorhanden ......sondern aktiv wie Modbus TCP abgefragt werden. Leider habe ich nur sehr wenig Erfahrung bzw bin gerade erst daran mir Erfahrung anzueignen.

/*
(c) C.Epe, April 2022, use at your own risk!
Software Version 2.0:
- read status back from HMIP-MOD-RC8
- in setup function: trigger all "off"-Buttons of HMIP-MOD-RC8 on startup
- in loop function: check if wifi is still connected, if not "try to reconnect" (see checkWifi function)
- in loop function: check status of HMIP-MOD-RC8 after sending pv excess change, when sending failed =>resend it after 5000ms + wiggleLeds
- reduced pulse length for HMIP-MOD-RC8 to reduce the danger of max. duty cycle error
- implemented getTime-function, see "whatTimeisIt" to display time. Don´t forget to set timezone!
- all analogWrite(ledblue,_) are set to digitalWrite(ledblue,_), please set all resistors (R1, R2, R3) to 500-600 Ohm to get the LEDs darker.
- watchdog implemented for recognizing system crash

HMIP-PV-RC8
- This codes connects to your wifi. This is done in the setup function. Don´t forget your wifi SSID and passwort into arduino_secret.h
- Reading UDP data is based on example "WifiNINA\WiFiUdpSendReceiveString"
- Set localPort and IPAddress when you are using other energy meter than SMA Energymeter
- Reading UDP multicast parameters data is customized to SMA Energy Meter!
- Set timezone, updatetime, waiting & threshold under "necessary varables"
- Serial monitor in Arduino IDE show usefull information for debugging!
 */
 
#include <SPI.h>
#include <WiFiNINA.h>
#include <Adafruit_SleepyDog.h>


#include "additional_functions.h"
#include "arduino_secrets.h"  
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;      // your network SSID (name)
char pass[] = SECRET_PASS;      // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;    // the WiFi radio's status

///////UDP variables & initialisation
unsigned int localPort = 502;                      // local port to listen on
IPAddress Energymeter = IPAddress(192,168,1,205); // ip address to listen to
char packetBuffer[600];                             //buffer to hold incoming packet
char  ReplyBuffer[] = "acknowledged";               // a string to send back

WiFiUDP Udp;

#define status_R 9 // Status Pin of HMIP-MOD-RC8  "Error" - Maybe future use
#define status_G 10 // Status Pin of HMIP-MOD-RC8  "Job done!" - Maybe future use  
#define status_S 11 // Status Pin of HMIP-MOD-RC8  "Running activity" - Maybe future use

#define ledgreen A4 // Indicator led for pv excess
#define ledred A5   // Indicator led when there is no pv excess
#define ledblue A3  // Indicator led when HMIP-MOD-RC8 any of his inputs are set to status "on"


//Pins to HMIP-MOD-RC8
int DigiOut[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};

//********************************************************************
// Necessary varables
static bool previous_state = false;
bool pvExcess = false;
static bool previous_pvExcess;
bool startcounter = false;      // Set when counter2 should be active
bool state = false;             // Used to switch on and off
bool flag = false;              // indicate pv excess for more than waiting  time
int counter = 0;        // Counter for updating serial data
int counter2 = 0;       // Counter for time to wait before changing pv excess indication
int updatetime = 1;     // Updatetime for serial data, pv excess data update and waiting count
int waiting = 60;       // wait x seconds before reporting HMIP-MOD-RC9 that pv excess is present. Used in LowPass()
unsigned long threshold = 0; // set this value (Watts). When pv excess is higher than this value for more than "waiting" seconds 
                            // HMIP-MOD-RC8 will be turned on
bool hmipstate = false; //status for feedback coming from HMIP-MOD-RC8
uint8_t pulselength = 20;//pulse length of pulse send to HMIP-MOD-RC8 in Milliseconds

//set your time zone here, example: Europe/​Berlin UTC +2
uint8_t timezone = 2;

//********************************************************************

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // Set up led pins 
  pinMode(ledgreen, OUTPUT);
  pinMode(ledred, OUTPUT);
  pinMode(ledblue, OUTPUT);

  //Setup Inputs for status pin coming from HMIP-MOD-RC9
  pinMode(status_R, INPUT);
  pinMode(status_G, INPUT);
  pinMode(status_S, INPUT);

  // Set up DigiOuts to HMIP-MOD-RC8
  for(int i=0; i<=8; i++){
    pinMode(DigiOut[i], OUTPUT);
  }
  
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }
  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {   
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    //wiggle leds to indicate that HMIP-PV-RC8 is trying to connect to the wifi
    wiggleLeds(ledred, ledgreen); 
  }
 
  // you're connected now, so print out the data:
  Serial.print("You're connected to the network");
  printCurrentNet();
  printWifiData();
  
  Serial.print("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  Udp.beginMulticast(Energymeter, localPort);
  Serial.println(" connected udp multicast");
  // start UDP service
  getUDPdataSetup();
 
    
  //uncomment if necessary
  //printCurrentNet();

  //write time text  
  Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
  
  //trigger all "off"-Buttons of HMIP-MOD-RC8 
  digitalWrite(DigiOut[1], HIGH);
  delay(pulselength);
  digitalWrite(DigiOut[1], LOW);
  delay(1200); //Wait for HMIP-MOD-RC8 status_S (100 ms) + status_G (400ms) + status_R (600ms)+buffer (100ms) 

  digitalWrite(DigiOut[3], HIGH);
  delay(pulselength);
  digitalWrite(DigiOut[3], LOW);
  delay(1200); //Wait for HMIP-MOD-RC8 status_S (100 ms) + status_G (400ms) + status_R (600ms)+buffer (100ms) 
   
  digitalWrite(DigiOut[5], HIGH);
  delay(pulselength);
  digitalWrite(DigiOut[5], LOW);
  delay(1200); //Wait for HMIP-MOD-RC8 status_S (100 ms) + status_G (400ms) + status_R (600ms)+buffer (100ms) 

  digitalWrite(DigiOut[7], HIGH);
  delay(pulselength);
  digitalWrite(DigiOut[7], LOW);
  delay(1200); //Wait for HMIP-MOD-RC8 status_S (100 ms) + status_G (400ms) + status_R (600ms)+buffer (100ms) 

  //start watchdog
  Watchdog.enable(10000); // if not reset within period in Milliseconds system will be restartet. Don´t go unter 10.000ms!
}


// start the loop
void loop() {

  // reset watchdog
  Watchdog.reset();
   
  // check Wifi
  checkWifi();
  
  // check current hours
  uint8_t hours = whatTimeIsIt(timezone);
  
  //getUDPdata() reads multicast packet (600 Byte of data) and returns the amount of pv excess in "deci watt" 100 dW = 10 W
  unsigned long Einspeisung = getUDPdata();

  //only lowpass or change state when there is no error from HMIP-MOD-RC8
  if (!digitalRead(status_R)){
    //LowPass() takes "Einspeisung" and "low passes" the data. So quick changes of "Einspeisung" will be smoothed
    state = LowPass(Einspeisung);
  }
  
  //update time set above!
  delay(1000*updatetime);

  // send to HMIP-MOD-RC8 only when state has changed. Example: Switching Channel 1 & 2.  
  if(previous_state!=state){
      // light up blue led and switch HMIP-MOD-RC8
      if(state){
        digitalWrite(ledblue, HIGH);
        hmipstate = false; 
        while (!hmipstate){
          //Set impulse (50 ms duration) to DigiOut2 correspondig to "on"         
          digitalWrite(DigiOut[2], HIGH);
          delay(pulselength);
          digitalWrite(DigiOut[2], LOW);
          delay(400); //wait for HMIP-MOD-RC8 sending
          // if sending was successfull abort while loop, else re-send it.
          if (digitalRead(status_G)){
            hmipstate = !hmipstate;
            Serial.println("HMIP-MOD-RC8 acknowledged!");
            for (int t=0; t<=8; t++){
              digitalWrite(ledblue, LOW);
              delay(100); 
              digitalWrite(ledblue, HIGH);
              delay(100); 
            }
          }
          //if sending to HMIP failed, reset watchdog and wait 5 seconds before resending.
          else {
            Watchdog.reset(); 
            Serial.print("HMIP-MOD-RC8 not respondig or cannot send to Access Point!");
            delay(3000);
            Serial.println("Resending...");
            delay(1000);
            // indicate that we are here in this while-Loop
            wiggleLeds(ledblue, ledgreen); 
          }  
        } 
      } 
    else{
      digitalWrite(ledblue, LOW);
      hmipstate = false; 
      while (!hmipstate){
        //Set impulse (50 ms duration) to DigiOut1 correspondig to "off" 
        digitalWrite(DigiOut[1], HIGH);
        delay(pulselength);
        digitalWrite(DigiOut[1], LOW);
        delay(400); //wait for HMIP-MOD-RC8 sending
        // if sending was successfull abort while loop, else re-send it.
        if (digitalRead(status_G)){
          Serial.println("HMIP-MOD-RC8 acknowledged!");
          hmipstate = !hmipstate;
          for (int t=0; t<=8; t++){
            digitalWrite(ledblue, HIGH);
            delay(100); 
            digitalWrite(ledblue, LOW);
            delay(100); 
          }
        }  
        //if sending to HMIP failed, reset watchdog and wait 5 seconds before resending.
        else {
          Watchdog.reset();
          Serial.print("HMIP-MOD-RC8 not respondig or cannot send to Access Point!");
          delay(3000);
          Serial.println("Resending...");
          delay(1000);
          // indicate that we are here in this while-Loop
          wiggleLeds(ledblue, ledred);  
        }  
      }
    }
  }   
  // update state
  previous_state=state; 
}

// Lowpass function to prevent sudden change of "Einspeisung" status effecting HMIP
bool LowPass(unsigned long Einspeisung){ 
  //If there is pv excess, set pvExcess and light up red green
  //Einspeisung is returned in "deci watt" 100 dW = 10 W
  if (Einspeisung/10>threshold){
    pvExcess = true;
    Serial.print("PV Excess! Use it :-)");
    digitalWrite(ledred, LOW);
    digitalWrite(ledgreen, HIGH);     
    //if status of pvExcess has changed start counter2, remember: function is called every "updatetime" seconds
    if (previous_pvExcess != pvExcess){
      Serial.println("****PV excess YES!");
      startcounter = true;     
      previous_pvExcess = pvExcess;
      Serial.print(previous_pvExcess); 
    }
  }
  //If there is no pv excess, set pvExcess to false and light up red led
  else {
    pvExcess = false;
    digitalWrite(ledgreen, LOW);
    digitalWrite(ledred, HIGH);
    //if status of pvExcess has changed start counter2, remember: function is called every "updatetime" seconds
    if (previous_pvExcess != pvExcess){
      Serial.println("****Change to no PV excess!");
      startcounter = true;
      previous_pvExcess = pvExcess;
    }
  }
  // if startcounter is true count up
  if (startcounter){
    counter2++;
    // for Debbugging
    //Serial.print("counter2:");
    Serial.println(" ");
    Serial.print(counter2); // times "updatetime" because function is called every "updatetime" seconds
    Serial.print(" seconds since pv excess status change to ");
    Serial.print(pvExcess);
    Serial.print(" ");
  }
  //If there is no other change within waiting time update flag and tell loop function to set HMIP-MOD-RC8
  if (counter2 >= waiting) {
    if (pvExcess){
      flag = true;
    }
    else{
      flag = false;
    }
    counter2 = 0;   // reset counter
    startcounter = false; // stop counting
  }
  return flag; 
}

//check wifi connection function
void checkWifi(){
  //check if wifi is still connected
  if (WiFi.status() != WL_CONNECTED){
    //trigger all "off"-Buttons of HMIP-MOD-RC8 
      Serial.println("---------------Wifi connection lost!----------------");
      Serial.println("-------Trigger off all HMIP-MOD-RC8 buttons---------");
      digitalWrite(ledblue, LOW);
      
      digitalWrite(DigiOut[1], HIGH);
      delay(pulselength);
      digitalWrite(DigiOut[1], LOW);
      delay(1200); //Wait for HMIP-MOD-RC8 status_S (100 ms) + status_G (400ms) + status_R (600ms)+buffer (100ms) 

      digitalWrite(DigiOut[3], HIGH);
      delay(pulselength);
      digitalWrite(DigiOut[3], LOW);
      delay(1200); //Wait for HMIP-MOD-RC8 status_S (100 ms) + status_G (400ms) + status_R (600ms)+buffer (100ms) 
   
      digitalWrite(DigiOut[5], HIGH);
      delay(pulselength);
      digitalWrite(DigiOut[5], LOW);
      delay(1200); //Wait for HMIP-MOD-RC8 status_S (100 ms) + status_G (400ms) + status_R (600ms)+buffer (100ms) 

      digitalWrite(DigiOut[7], HIGH);
      delay(pulselength);
      digitalWrite(DigiOut[7], LOW);
      delay(1200); //Wait for HMIP-MOD-RC8 status_S (100 ms) + status_G (400ms) + status_R (600ms)+buffer (100ms)   
  }
  while (WiFi.status() != WL_CONNECTED) {  
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    //wiggle leds to indicate that HMIP-PV-RC8 is trying to connect to the wifi
    if (WiFi.status() == WL_CONNECTED){
      // you're connected now, so print out the data:
      Serial.print("You're connected to the network");
      printCurrentNet();
      printWifiData();
      
      //restart UDP service
      Serial.print("\nStarting connection to UDP server...");
      // if you get a connection, report back via serial:
      Serial.println("\n connecting udp multicast");
      Udp.beginMulticast(Energymeter, localPort);
      Serial.println("\n connected udp multicast");
      // start UDP service
      getUDPdataSetup();
    }
    //wiggle leds to indicate that HMIP-PV-RC8 is trying to connect to the wifi
    wiggleLeds(ledred, ledgreen);  
  }
}

unsigned long getUDPdata() {
  unsigned long Einspeisung;
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {

    // read the packet into packetBufffer
    int len = Udp.read(packetBuffer, 600);
    //Serial.println(len);
    if (len > 0) {
      packetBuffer[len] = 0;
    }

    // See Packet information here:
    // http://www.eb-systeme.de/?page_id=1240
    // Someone has done a great job here!
    //
    Serial.println("***********************************");
    //print momentaner Bezug 
    Serial.print("Bezug (Watt): ");
    unsigned long highWordBezug = word(packetBuffer[32], packetBuffer[33]);
    unsigned long lowWordBezug = word(packetBuffer[34], packetBuffer[35]);
    unsigned long Bezug = highWordBezug << 16 | lowWordBezug;
    Serial.print(Bezug/10); //Bezug is returned in "deci watt" 100 dW = 10 W
    
    //print momentane Einspeisung 
    Serial.print(" Einspeisung (Watt): ");
    unsigned long highWordEinspeisung = word(packetBuffer[52], packetBuffer[53]);
    unsigned long lowWordEinspeisung = word(packetBuffer[54], packetBuffer[55]);
    Einspeisung = highWordEinspeisung << 16 | lowWordEinspeisung;
    Serial.print(Einspeisung/10); //Einspeisung is returned in "deci watt" 100 dW = 10 W
    Serial.print("  ");
  } 
  //Simulate pv excess for x seconds only for debugging - uncomment if you want to use it.
  /*counter++;
  Serial.print("Cyclecounter: ");
  Serial.println(counter);
  if (counter<=10){ // 10 seconds
    Einspeisung = 5000;   
  }
  else{
    Einspeisung = 0;
  }
  if (counter>=40){
    counter =0;
  }
  //Simulate pv excess end
  */
  return Einspeisung; //Einspeisung is returned in "deci watt" 100 dW = 10 W
}



void getUDPdataSetup() {
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remoteIp = Udp.remoteIP();
    Serial.print(remoteIp);
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBufffer
    int len = Udp.read(packetBuffer, 600);
    //Serial.println(len);
    if (len > 0) {
      packetBuffer[len] = 0;
    }

    // See Packet information here:
    // http://www.eb-systeme.de/?page_id=1240
    // Someone has done a great job here!
    //
    Serial.print("***********************************");
    Serial.println("Contents:");
    //print vendor of device (SMA Energy Meter)
    Serial.print("Vendor: ");
    for (int i=0; i<=2;i++){
      Serial.print(packetBuffer[i]);
    }
    Serial.println();
    
    //print SUSyID of device
    Serial.print("SUSyID: ");
    unsigned long susyID = word(packetBuffer[20], packetBuffer[21]);
    Serial.println(susyID);

    
    //print serial number of device
    Serial.print("Serial number: ");
    unsigned long highWordSerial = word(packetBuffer[20], packetBuffer[21]);
    unsigned long lowWordSerial = word(packetBuffer[22], packetBuffer[23]);
    unsigned long serial = highWordSerial << 16 | lowWordSerial;
    Serial.println(serial);
  }
}


void printWifiData() {
  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  Serial.println(ip);

  // print your MAC address:
  byte mac[6];
  WiFi.macAddress(mac);
  Serial.print("MAC address: ");
  printMacAddress(mac);
}

void printCurrentNet() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print the MAC address of the router you're attached to:
  byte bssid[6];
  WiFi.BSSID(bssid);
  Serial.print("BSSID: ");
  printMacAddress(bssid);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.println(rssi);

  // print the encryption type:
  byte encryption = WiFi.encryptionType();
  Serial.print("Encryption Type:");
  Serial.println(encryption, HEX);
  Serial.println();
}

void printMacAddress(byte mac[]) {
  for (int i = 5; i >= 0; i--) {
    if (mac[i] < 16) {
      Serial.print("0");
    }
    Serial.print(mac[i], HEX);
    if (i > 0) {
      Serial.print(":");
    }
  }
  Serial.println();
}

Um das passive UDP-Abhören durch aktive Modbus-TCP-Abfragen zu ersetzen, benötigen Sie die Modbus-Registerkarte oder die API-Dokumentation Ihres Wechselrichters oder Energiezählers. Diese gibt an, welche Register den Werten entsprechen, die Sie auslesen möchten, wie beispielsweise Momentanleistung, Einspeisung, Verbrauch, Spannung oder Strom. Ohne diese Informationen können die Modbus-Anfragen nicht korrekt erstellt werden.

Sobald Sie die Registerübersicht haben, würde der Arduino-Code eine Modbus-TCP-Client-Bibliothek wie ArduinoModbus verwenden, sich mit der IP-Adresse und dem Port des Wechselrichters verbinden und die gewünschten Register regelmäßig auslesen. Die zurückgegebenen Bytes würden dann in aussagekräftige Werte umgewandelt und in die bestehende Low-Pass- und HMIP-MOD-RC8-Logik Ihres Sketches eingespeist.

Vielen Dank für die schnelle Antwort. Das mit den Registern ist mir bekannt bzw Modbus TCP kenne ich. Nur eben das Coding für den Arduino bin ich Anfänger.
Hier würde ich eventuell ein Mustercoding benötigen

Sun2000 Modbus Register – Debacher-Wiki

ArduinoModbus/examples/TCP at master · arduino-libraries/ArduinoModbus · GitHub

Hat hier schon mal jemand probiert. Bitte #6 auch beachten.

Actually, I got it working. This what I used. Hope it helps.

I was using the oopla kit to show the data.

#include <SPI.h>
#include <WiFiNINA.h> // for MKR WiFi 1010
#include <Arduino_MKRIoTCarrier.h>
#include <stdio.h>

MKRIoTCarrier carrier;

char ssid[] = "YOUR_ORIGINAL_SSID_NAME";
char pass[] = "your_super_complex_password";

int status = WL_IDLE_STATUS;

IPAddress server(192, 168, 1, 100);
int port = 6607;

WiFiClient modbus;
uint16_t transactionId = 0;

const byte FNC_READ_REGS = 0x03;

uint16_t whiteColor = 0xFFFF;
uint16_t blackColor = 0x0000; 
uint16_t redColor = 0xF800;
uint16_t greenColor = 0x07E0;
uint16_t blueColor = 0x001F; 

void setup() {
  CARRIER_CASE = true;

  //Initialize serial and wait 5 secs max for port to open:
  unsigned long timer = millis();
  Serial.begin(9600);
  while (!Serial && (millis() - timer) < 5000) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  if (!carrier.begin())
  {
    Serial.println("Carrier not connected, check connections");
    while (1);
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(5000);

    // you're connected now, so print out the status:
    printWifiStatus();

    // Set default led colours
    //carrier.leds.fill(carrier.leds.Color(255, 0, 0), 0, 1);
    //carrier.leds.setBrightness(5);
    //carrier.leds.show();
  }
}

void loop() {
  //carrier.Buttons.update();	// Read the buttons state
  //Check if the Button 0 is being touched
  //if (carrier.Buttons.getTouch(TOUCH0)){
  //  Serial.println("Touching Button 0");
  //}
  
  if (!modbus.connected()) {
    modbus.stop();
    Serial.println("Connecting to ModBus TCP:");
    if (!modbus.connect(server, port))
      Serial.println("Error connecting to ModBus.");
    modbus.setTimeout(2000);
  }

  // ACTIVE_POWER address is 32080
  // POWER_METER_ACTIVE_POWER address is 37113
  clearModbusBuffer();
  int32_t activePower = readRegister (32080);
  clearModbusBuffer();
  int32_t powerMeter = readRegister (37113);
  int32_t consumption = activePower - powerMeter;
  printValues(activePower, powerMeter, consumption);

  //Serial.println("Closing connection:");
  //modbus.stop();
  delay(4000);
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

int32_t readRegister (int addr) {
  Serial.print("Sending request for address: ");
  Serial.println(addr);
  // Increase transaction identifies and split in two bytes
  byte highByte = (transactionId++ >> 8) & 0xFF;
  byte lowByte = transactionId & 0xFF;
  byte request[] = {highByte, lowByte, 0, 0, 0, 6, 0, FNC_READ_REGS, (byte) (addr / 256), (byte) (addr % 256), 0, 2};
  modbus.write(request, sizeof(request));
  modbus.flush();
  
  unsigned long startTime = millis();
  while (modbus.available() < 13 && (millis() - startTime) < 2000) {
    delay(10); // Wait 10ms until next check
  }
  
  // Modbus TCP response format
  // Example: "0 1 0 0 0 7 0 3 4 0 0 0 0"
  //   Transaction Identifier (2 bytes): 0 1
  //   Protocol Identifier (2 bytes): 0 0
  //   Length (2 bytes): 0 7
  //   Unit Identifier (1 byte): 0
  //   Function Code (1 byte): 3 (Read Holding Registers)
  //   Byte Count (1 byte): 4 (4 bytes of data)
  //   Data Payload (4 bytes): 0 0 0 0
  byte response[13];
  int i = 0;
  Serial.print("Modbus TCP response: ");
  if (modbus.available() >= 13) {
    while (modbus.available() && i < 13) {
      byte b = modbus.read();
      response[i++] = b;
      Serial.print(b, HEX);
      Serial.print(" ");
    }
    Serial.println("Finished.");
  } else {
    Serial.println("Error.");
    return -1;
  }

  uint16_t transactionIdentifier = (response[0] << 8) | response[1];
  uint16_t protocolIdentifier = (response[2] << 8) | response[3];
  uint16_t length = (response[4] << 8) | response[5];
  byte unitIdentifier = response[6];
  byte functionCode = response[7];
  byte byteCount = response[8];
  int32_t registerValue = (response[9] << 24) | (response[10] << 16) | (response[11] << 8) | response[12];

  Serial.print("Register Value: ");
  Serial.println(registerValue);

  return registerValue;
}

void printValues(int32_t activePower, int32_t powerMeter, int32_t consumption) {
  char buffer[20];

  // Reset display
  carrier.display.setRotation(0);
  carrier.display.fillScreen(blackColor);

  float activePowerFloat = activePower / 1000.0;
  snprintf(buffer, sizeof(buffer), "%.1f", activePowerFloat);
  String firstLine = String(buffer) + "kW";
  carrier.display.setTextSize(4);
  carrier.display.setTextColor(greenColor);
  carrier.display.setCursor(65, 70);
  carrier.display.print(firstLine);

  uint16_t color = powerMeter < 0 ? redColor : whiteColor;
  String secondLine = formatPowerValues(consumption, powerMeter);
  carrier.display.setTextSize(3);
  carrier.display.setTextColor(color);
  carrier.display.setCursor(25, 120);
  carrier.display.print(secondLine);
}

String formatPowerValues(float consumption, float powerMeter) {
  char buffer[20];
  
  // Convertir consumption y powerMeter a kW y redondear a 1 decimal
  consumption /= 1000.0;
  powerMeter /= 1000.0;

  // Convertir los números a cadena con un solo decimal
  snprintf(buffer, sizeof(buffer), "%.1f", consumption);
  String consumptionStr = String(buffer);

  snprintf(buffer, sizeof(buffer), "%.1f", abs(powerMeter));
  String powerMeterStr = String(buffer);

  // Añadir la flecha en función de si powerMeter es negativo o no
  String arrow = powerMeter < 0 ? "<" : ">";

  // Combinar las cadenas y devolver el resultado
  return consumptionStr 
  + "kW" + arrow + powerMeterStr + "kW";
}

void clearModbusBuffer() {
  while (modbus.available()) {
    modbus.read();
  }
}
1 Like