Dezimalzahl aus Char-Datensatz auslesen

mach mal static float leistung = -1;

Annahme:
ansonsten ist die Leistung beim nächsten Durchlauf ja wieder -1 und somit kommst in den else Zweig

Serial.print Ausgaben im Schalten würden dir das zeigen.

Mit static flaot wird im seriellen Monitor ununterbrochen die Leistung angezeigt, aber wohl das Protokoll nicht mehr gelesen.

Kannst Du mal bitte das loop austauschen:

void loop()
{
  float leistung = -1;
  static float lastLeistung = 0;
  recvWithEndMarker(leistung);
  if (leistung != lastLeistung)
  {
    Serial.print(F("Leistung = "));
    Serial.println(leistung, 3);
    lastLeistung = leistung;
  }
  if (leistung > 0.050)
  {
    digitalWrite(3, LOW);
  }
  else
  {
    // turn LED off:
    digitalWrite(3, HIGH);
  }
}

Ich will wissen, was da angezeigt wird, wenn es zu Überprdokution kommt. und wann der wieder schalten müsste.

gelesen wird sicher, du siehst es nur nicht.

setz deinen Schaltungs-IF mal in deinen Ausgabe-if

    float leistung = -1;  // doch wieder jeden loop neu:
    recvWithEndMarker(leistung);
    if (leistung >= 0) {
      Serial.print(F("Leistung = "));
      Serial.println(leistung, 3);
      if (leistung > 0.050) {
        Serial.println("true");
        digitalWrite(3, LOW);
      } else {
        Serial.println("false");
        digitalWrite(3, HIGH);
      }
    }
1-0:1.8.1(003113.724*kWh)
1-0:1.8.2(001108345*kWh)
1-0:2.8.0(007041373*kWh)
1-0:2.8.2(000052.335*kWh)
1-0:327.08236.2*V)
1-0:52.7.0(238.0*V)
1-0:0270(23a.7*V)
1-0:31.7.0(000*A)
1-0:51.7.0(000*A)
1-0:71.7.0(000*A)
1-0:2.7.0(00.136*kW)
Leistung = 0.136
1Leistung = -1.000
-0:1.7.0(9
 17E8

1-0:1.8.1(003113.814*kWh)
1-0:1.8.2(001108.345*kWh)
1-0:2.8.1(007041.380*kWh)
1-0:2.8.2(000052.335*kWh)
1-0:32.7.0(235.8*V)
1-0:52.7.0(238.4*V)
0-0:72.7.0(238.0*V)
1-0:31.7.0(000*A)
1-0:51.7.0(000*A)
1-0:71.7.0(000*A)
1-0:2.7.0(00.139*kW)
Leistung = 0.139
true
1-0:1.7.0()
!32E4

So scheint es zu funktionieren. Jetzt schaltet das Relais zwischen 0.139 und 0.000.

Da ist er.
@noiasca kannst Du das irgendwie ändern, das im recvWithEndMarker der letzte Wert gespeichert wird und der zurück gegeben, wenn noch kein aktueller?

Zwischendurch:

so könnte man das ganze variabel halten und in eine Klasse stopfen mit dem Ziel dies in eine library auszulagern:

/*
   Semax Smartmeter with DMSR
   https://forum.arduino.cc/t/dezimalzahl-aus-char-datensatz-auslesen/934748
   Started with Example 4 https://forum.arduino.cc/t/serial-input-basics-updated/382007/3

   https://www.netbeheernederland.nl/_upload/Files/Slimme_meter_15_a727fce1f1.pdf

   message examples
   1-0:71.7.0(004A)
   1-0:2.7.0(00.000*kW)
   1-0:1.7.0()

   by noiasca - with a little help from wmo158
*/

struct Data
{
  char timestamp[14];                      // 13 + null
  char equipmentIdentifier[32];            // up to 96 in protocol
  float electricityDeliveredToClientT1;
  float electricityDeliveredByClientT1;
  float electricityDeliveredToClientT2;
  float electricityDeliveredByClientT2;
  float instantaneousVoltageL1;
  float instantaneousVoltageL2;
  float instantaneousVoltageL3;
  float instantaneousCurrentL1;
  float instantaneousCurrentL2;
  float instantaneousCurrentL3;
  float actualElectricityPowerReceived;
  float actualElectricityPowerDelivered;
  bool isDirty = true;                      // at least one value was changed
};

class Smartmeter {
    static const byte numChars = 32;  // receiver buffer size
    char receivedChars[numChars];     // an array to store the received data
    boolean newData = false;
    Stream &stream;
    void (*cbOnNewData)();            // gets called after we received a full message (=after the CRC)
    
  public:
    Data data;                        // MISSING: make protected and provide get functions
  
    Smartmeter (Stream &stream) : stream(stream) {}

    void setOnNewData(void (*cbOnNewData)())
    {
      (*this).cbOnNewData = cbOnNewData;
    }

    void update()          // was recvWithEndMarker();
    {
      static byte ndx = 0;
      char endMarker = '\n';
      char rc;
      if (stream.available() > 0) {
        rc = stream.read();
        if (rc != endMarker) {
          receivedChars[ndx] = rc;
          ndx++;
          if (ndx >= numChars) {
            ndx = numChars - 1;
          }
        }
        else {
          receivedChars[ndx] = '\0'; // terminate the string
          ndx = 0;
          newData = true;
          parseLine();
        }
      }
    }

    void parseLine() {
      if (newData == true) {
        // output all
        //Serial.print(F("This just in ... "));
        //Serial.println(receivedChars);
        //int success = -1;
        char* ptrBracket = strchr(receivedChars, '(');
        if (!strncmp(receivedChars, "0:1.0.0(", 8))
        {
          //Serial.println(F("D time"));
          strncpy(data.timestamp, ptrBracket + 1, sizeof(data.timestamp) - 1);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "0-0:96.1.1(", 11))
        {
          const size_t length = sizeof(data.equipmentIdentifier) - 1;
          size_t lengthRec = strlen(receivedChars) - 12;
          lengthRec = min(length, lengthRec);
          strncpy(data.equipmentIdentifier, ptrBracket + 1, lengthRec);
          data.equipmentIdentifier[lengthRec] = '\0';
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:1.7.0(", 10))
        {
          data.actualElectricityPowerDelivered = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:2.7.0(", 10))
        {
          data.actualElectricityPowerReceived = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
          //userFunction();                                                          // das ist offenbar die Message die den TO interessiert
        }
        else if (!strncmp(receivedChars, "1-0:1.8.1(", 10))
        {
          data.electricityDeliveredToClientT1 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:1.8.2(", 10))
        {
          data.electricityDeliveredByClientT1 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:2.8.1(", 10))  // to be checked
        {
          data.electricityDeliveredToClientT2 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:32.7.0(", 10))
        {
          data.instantaneousVoltageL1 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:52.7.0(", 10))
        {
          data.instantaneousVoltageL2 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:72.7.0(", 10))
        {
          data.instantaneousVoltageL3 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:31.7.0(", 10))
        {
          data.instantaneousCurrentL1 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:51.7.0(", 10))
        {
          data.instantaneousCurrentL2 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (!strncmp(receivedChars, "1-0:71.7.0(", 10))
        {
          data.instantaneousCurrentL3 = strtod(ptrBracket + 1, NULL);
          data.isDirty = true;
        }
        else if (receivedChars[0] == '!')
        {
          // tbc check CRC
          data.isDirty = false;
          if(cbOnNewData) cbOnNewData();
          
        }
        //printAllData();
        newData = false;
      }
    }
};

//#include <AltSoftSerial.h>
//#define RX_PIN 8
//#define TX_PIN 9
//AltSoftSerial altSerial;
//Smartmeter smartmeter(altSerial);    // receive data from Smartmeter with altSerial

Smartmeter smartmeter(Serial);         // debugging with HW Serial

// user sketch specific variables and functions
constexpr byte indicatorPin = 3;
const float threasholdCurrent = 0.05;

// this function will be called each time we have received a new packet (=several lines)
void callbackOnNewData()
{
  printAllData();
  if (smartmeter.data.actualElectricityPowerReceived > threasholdCurrent)
  {
    Serial.println(F("true - lower"));
    digitalWrite(indicatorPin, LOW);
  }
  else
  {
    Serial.println(F("false - higher"));
    digitalWrite(indicatorPin, HIGH);
  }
}

void printAllData() // quick'n'dirty print
{
  Serial.print(F("timestamp                       ")); Serial.println(smartmeter.data.timestamp);
  Serial.print(F("equipmentIdentifier             ")); Serial.println(smartmeter.data.equipmentIdentifier);
  Serial.print(F("electricityDeliveredToClientT1  ")); Serial.println(smartmeter.data.electricityDeliveredToClientT1);
  Serial.print(F("electricityDeliveredByClientT1  ")); Serial.println(smartmeter.data.electricityDeliveredByClientT1);
  Serial.print(F("electricityDeliveredToClientT2  ")); Serial.println(smartmeter.data.electricityDeliveredToClientT2);
  Serial.print(F("electricityDeliveredByClientT2  ")); Serial.println(smartmeter.data.electricityDeliveredByClientT2);
  Serial.print(F("instantaneousVoltageL1          ")); Serial.println(smartmeter.data.instantaneousVoltageL1);
  Serial.print(F("instantaneousVoltageL2          ")); Serial.println(smartmeter.data.instantaneousVoltageL2);
  Serial.print(F("instantaneousVoltageL3          ")); Serial.println(smartmeter.data.instantaneousVoltageL3);
  Serial.print(F("instantaneousCurrentL1          ")); Serial.println(smartmeter.data.instantaneousCurrentL1);
  Serial.print(F("instantaneousCurrentL2          ")); Serial.println(smartmeter.data.instantaneousCurrentL2);
  Serial.print(F("instantaneousCurrentL3          ")); Serial.println(smartmeter.data.instantaneousCurrentL3);
  Serial.print(F("actualElectricityPowerReceived  ")); Serial.println(smartmeter.data.actualElectricityPowerReceived);
  Serial.print(F("actualElectricityPowerDelivered ")); Serial.println(smartmeter.data.actualElectricityPowerDelivered);
  Serial.print(F("isDirty                         ")); Serial.println(smartmeter.data.isDirty);
}

// Arduino setup and loop
void setup() {
  Serial.begin(115200);
  //altSerial.begin(115200);
  smartmeter.setOnNewData(callbackOnNewData); // register a callback onNewData
}

void loop() {
  smartmeter.update();
}

beim "testen" halt aufpassen, das Event "onNewData" feuert erst nach dem der CRC empfangen wurde. also mindestens eine neue Zeile senden und dann noch ein !

wenn man sich die Klasse und das Struct wegdenkt, ist der Sketch eigentlich sehr übersichtlich (finde ich ^^)

Gerne darf kritisch gewürdigt werden.

mit dem OOP verfolge ich jetzt einen anderen Ansatz. Damit stehen die Daten dauerhaft zur Verfügung (und auch ein dirty flag ob man gerade neue Daten empfängt).

möchte man mal den CRC auch berücksichtigen könnte man einfach die Daten trennen in ein "incomming/dirty" und die Übernahme in eine zweite Struktur "lastValid" ...
aber CRC16 ohne ausreichend Testdaten oder einem Device am Tisch tu ich mir jetzt nicht an :wink:

Dann mal als einfache Prototyp Library:
https://werner.rothschopf.net/microcontroller/202112_noiasca_smartmeter.htm