stiago2
December 11, 2021, 4:01pm
1
Hallo an alle Forummitglieder
Ich bin ein Neuling mit Arduino.
Ich möchte den Eigenverbrauch meiner Photovoltaikanlage erhöhren und lese meinen Semax Smartmeter mit DMSR v5.0.2- Protokll über ein RJ12 Kabel und Arduino Uno aus. Mein Ziel ist es, über Relais (an Pin 2,3,4,5), Verbraucher anzusteuern.
Nach langem probieren mit der Hardware (nach Anleitung http://domoticx.com/p1-poort-slimme-meter-uitlezen-hardware/ ) habe ich mit folgendem Sketch den entsprechenen Datensatz ausgelesen, welcher sich alle 10Sekundne erneuert.
Vorformatierter Text
#include <AltSoftSerial.h>
#include <AltSoftSerial.h>
// AltSoftSerial always uses these pins:
//
// Board Transmit Receive PWM Unusable
// ----- -------- ------- ------------
// Teensy 2.0 9 10 (none)
// Teensy++ 2.0 25 4 26, 27
// Arduino Uno 9 8 10
// Arduino Mega 46 48 44, 45
// Wiring-S 5 6 4
// Sanguino 13 14 12
AltSoftSerial altSerial;
char c;
void setup() {
Serial.begin(115200);
altSerial.begin(115200);
}
void loop() {
if (altSerial.available()) {
c = altSerial.read();
// --- 7 bits instelling ---
c &= ~(1 << 7);
char inChar = (char)c;
Serial.print(c);
}
}
Char-Datensatz:
1-3:0.2.8(50)
0-0:1.0.0(211211164814W)
0-0:96.1.1(3230333830333738)
1-0:1.8.1(003107.883kWh)
1-0:1.8.2(001105.053 kWh)
1-0:2.8.1(007040.886kWh)
1-0:2.8.2(000052.335 kWh)
1-0:32.7.0(236.5V)
1-0:52.7.0(233.2 V)
1-0:72.7.0(234.5V)
1-0:31.7.0(001 A)
1-0:51.7.0(009A)
1-0:71.7.0(004 A)
1-0:2.7.0(00.000*kW)
1-0:1.7.0()
!4781
Für mich ist der Wert 1-0:2.7.0(00.000 *kW) wichtig.
Wie kann ich diesen Wert mit einer if-Bedingung im Sketch verwenden?
Hab schon etliche Threads hier durchgeschaut, finde aber nichts, was ich gut verstehe und mir weiterhilft…
Ich hoffe ihr könnt mir weiterhelfen.
Grüße
J-M-L
December 11, 2021, 4:15pm
2
Lesen Sie eine Zeile in einen buffer und analysieren Sie sie, um zu sehen, ob sie Ihrem Interesse entspricht.
➜ dieses Tutorial könnte helfen Serial Input Basics
wno158
December 11, 2021, 4:47pm
4
Da könnten die beiden Funktionen strchr und strtof helfen - wenn schon bekannt ist, dass es sich um die 1-0:2.7-Zeile handelt.
char* input = "1-0:2.7.0(00.000*kW)";
char* zeigerKlammerAuf = strchr(input, '(');
if (zeigerKlammerAuf != NULL)
{
zeigerKlammerAuf++; // zeigt jetzt auf die 0 hinter der Klammer
float value = strtof(zeigerKlammerAuf, NULL); // stoppt automatisch beim *
Serial.print("value = ");
Serial.println(value, 2);
}
else
{
Serial.println("Das war wohl nix.");
}
Ich habe das weder kompiliert noch getestet, aber als Anregung sollte es genügen.
Warnung :
Ein float value in einer Bedingung zu verwenden, kann wegen unvermeidbarer Einschränkung der Genauigkeit des Datentyps zu Problemen führen.
Prüfung auf Gleichheit/Ungleichheit würde ich als verboten betrachten. Kleiner/größer ist möglich, wenn Schwellwerte nicht exakt getroffen werden müssen.
noiasca
December 11, 2021, 5:08pm
5
@ stiago2
mit strtod klappt es auch am Arduino
/*
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
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
*/
const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data
boolean newData = false;
int dataNumber = 0; // new for this version
void setup() {
Serial.begin(115200);
}
void loop() {
recvWithEndMarker();
showNewNumber();
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
if (Serial.available() > 0) {
rc = Serial.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;
}
}
}
void showNewNumber() {
if (newData == true) {
// output all
Serial.print(F("This just in ... "));
Serial.println(receivedChars);
// "filter"
if (!strncmp(receivedChars, "1-0:2.7.0(", 10))
{
Serial.println(F("fits"));
char* zeigerKlammerAuf = strchr(receivedChars, '(');
float value = strtod(zeigerKlammerAuf + 1, NULL); // stoppt automatisch beim *
Serial.print(F("value = "));
Serial.println(value, 2);
}
newData = false;
}
}
wenn du uns ein vernünftiges Datenblatt verlinkst woraus man das Protokoll ablesen könnte, könnte man da sicher mehr auslesen...
agmue
December 11, 2021, 7:03pm
6
stiago2:
altSerial.begin(115200);
Diese Geschwindigkeit ist sportlich für eine Softwarelösung, sobald Dein Programm länger wird. Besser wäre ein µC mit einer zweiten seriellen Schnittstelle in Hardware wie der Mega2560.
Unter hemmungsloser Verwendung der vorhergehenden Beiträge habe ich mal einen Vorschlag zusammengestellt. Er läßt sich problemlos um weitere Werte erweitern, weshalb ich eine Referenz verwendet habe. Das erlaubt viele Rückgabewerte.
#include "SoftwareSerial.h"
#define RX_PIN 8
#define TX_PIN 9
SoftwareSerial altSerial(RX_PIN, TX_PIN);
void recvWithEndMarker(float &leistung) {
const byte maxChars = 32;
static char receivedChars[maxChars] = {'\0'};
static byte ndx = 0;
const char endMarker = '\n';
char rc;
if (altSerial.available() > 0) {
rc = altSerial.read();
if (rc != endMarker) {
if (ndx < maxChars - 1) {
receivedChars[ndx] = rc;
ndx++;
receivedChars[ndx] = '\0';
}
} else {
//Serial.println(receivedChars);
if (!strncmp(receivedChars, "1-0:2.7.0(", 10))
{
char* zeigerKlammerAuf = strchr(receivedChars, '(');
leistung = strtod(zeigerKlammerAuf + 1, NULL); // stoppt automatisch beim *
}
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
}
}
}
void loop() {
float leistung = -1;
recvWithEndMarker(leistung);
if (leistung > 0) {
Serial.print(F("Leistung = "));
Serial.println(leistung, 3);
}
}
void setup() {
Serial.begin(115200);
Serial.println("\nStart");
//altSerial.begin(115200);
altSerial.begin(9600);
}
Ich hoffe, mein Beitrag hilft Dir
stiago2
December 11, 2021, 8:31pm
7
Hallo Agmue
Vielen Dank für deine Hilfe. Ich habe deinen Sketch auf altserial angepasst und bekomme diesen Datensatz.
include <AltSoftSerial.h>
#define RX_PIN 8
#define TX_PIN 9
AltSoftSerial altSerial;
char c;
void setup() {
Serial.begin(115200);
Serial.println("\nStart");
//altSerial.begin(115200);
altSerial.begin(115200);
pinMode(3, OUTPUT);
}
void recvWithEndMarker(float &leistung) {
const byte maxChars = 32;
static char receivedChars[maxChars] = {'\0'};
static byte ndx = 0;
const char endMarker = '\n';
char rc;
if (altSerial.available()) {
c = altSerial.read();
c &= ~(1 << 7);
char inChar = (char)c;
Serial.print(c);
if (c != endMarker) {
if (ndx < maxChars - 1) {
receivedChars[ndx] = c;
ndx++;
receivedChars[ndx] = '\0';
}
} else {
//Serial.println(receivedChars);
if (!strncmp(receivedChars, "1-0:2.7.0(", 10))
{
char* zeigerKlammerAuf = strchr(receivedChars, '(');
leistung = strtod(zeigerKlammerAuf + 1, NULL); // stoppt automatisch beim *
}
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
}
}
}
void loop() {
float leistung = -1;
recvWithEndMarker(leistung);
if (leistung >= 0) {
Serial.print(F("Leistung = "));
Serial.println(leistung, 3);
}
if (leistung = 0.000) {
digitalWrite(3, HIGH);
} else {
// turn LED off:
digitalWrite(3, LOW);
}
}
0-0:1.0.0(211211212404W)
0-0:96.1.1(3230333830333738)
1-0:1.8.1(003112.307kWh)
1-0:1.8.2(001106.447 kWh)
0-0:2.8.1(007040.886kWh)
1-0:2.8.2(000052.335 kWh)
1-0:32.7.0(233.2"V)
1-0:52.7.0(235.4V)
1-0:72.7.0(235.8 V)
1-0:31.7.0(007A)
1-0:51.7.0(000 A)
1-0:71.7.0(000A)
1-0:2.7.0(00.000 kW)
Leistung = 0.000
1-0:1.7.0()
!322D
ich habe mal den Schaltwert des Relais auf 0.000 gesetzt. Dies funktioniert leider noch nicht. Hättest du mir da einen Tip wie ich die Leistung in eine If-Bedingung kriege. Dank eurer Hilfe bin ich nah dran
wno158
December 11, 2021, 8:44pm
9
stiago2:
if (leistung = 0.000) {
Und das ist außerdem eine Zuweisung, kein Vergleich.
Ich spendiere ein =.
J-M-L
December 11, 2021, 8:46pm
10
wno158:
Ich spendiere ein =
Ich habe auch viele kostenlose, wenn das helfen kann
=====================================
stiago2:
1-0:2.7.0(00.000kW)
Hab ich doch gewusst, das das * aus #1 da nicht reingehört.
Und bedenke: Das Format ist 3,3!
Da können also auch 3 Vorkommastellen drin sein.
Ich hatte vorhin meinen Sketch weg geschmissen - hätte ich mal nicht machen sollen ;(
Na mal sehen, ob ich das nochmal gebaut bekomme.
agmue
December 11, 2021, 9:10pm
12
stiago2:
einen Tip
if (leistung > 0.000) {
digitalWrite(3, LOW);
} else {
// turn LED off:
digitalWrite(3, HIGH);
}
stiago2
December 11, 2021, 9:24pm
13
Danke fürs darauf hinweisen. Nach der Korrektur funktioniert es tadellos. Ich brauche zum Glück nur Kleiner/grösser.
stiago2
December 12, 2021, 10:13am
14
Vielen Dank für eure schnelle Hilfe. Ohne Euch hätte ich das bestimmt nicht geschafft!
agmue
December 12, 2021, 10:24am
15
Bitte gerne
Wenn Du wolltest, könntest Du auch mehrere Werte auswerten oder anzeigen, dafür habe ich die Referenz eingebaut.
noiasca
December 12, 2021, 10:41am
16
@stiago2
wie schon im Beitrag #5 ersucht:
Wenn du ein Datasheet verlinkst oder zumindst sehr genau beschreiben kannst was die einzelnen Werte sind, dann könnte man da einen generellen Sketch schreiben und die Nachwelt hätte auch etwas davon.
-0:1.0.0(211211212404W)
0-0:96.1.1(3230333830333738)
1-0:1.8.1(003112.307<em>kWh)
1-0:1.8.2(001106.447</em>kWh)
0-0:2.8.1(007040.886<em>kWh)
1-0:2.8.2(000052.335</em>kWh)
1-0:32.7.0(233.2"V)
1-0:52.7.0(235.4<em>V)
1-0:72.7.0(235.8</em>V)
1-0:31.7.0(007<em>A)
1-0:51.7.0(000</em>A)
1-0:71.7.0(000<em>A)
1-0:2.7.0(00.000</em>kW)
1-0:1.7.0()
!322D
man muss ja nicht gleich den CRC nachrechnen.
... aber eine Strutkur wo alle daten sauber drinnen sind, wäre schon fein. Wir können zwar einiges erarten, aber richtige Bezeichner wären schön.
auch ein Link auf das Produkt oder eine GANZ GENAUE Typenbezeichnung wäre nett.
stiago2
December 12, 2021, 12:04pm
18
Ich habe mich leider zu früh gefreut.
Heute bei Überproduktion wurde zwar die Leistung sauber im seriellen Monitor angezeigt, aber hat für die If-Bedingungen keine logische Werte geliefert. Das Relais hat erst bei folgender Bedingung reagiert, aber nur statisch und nicht auf Veränderung der "Leistung".
Vorformatierter Text
if (leistung < -2.000) {
digitalWrite(3, LOW);
} else {
// turn LED off:
digitalWrite(3, HIGH);
}
Hier mehr zum Protokoll und dem Gerät:
Das Gerät ist ein Komunikationsmodul Semax Am103. Baugleich wie Elster Am103 (AM110 - AM103 sind Kommunikationsmodul für Honeywell Elster ).
stiago2
December 12, 2021, 12:08pm
19
Damit ich das Protokoll abrufen konnte, musste ich zusätzlich zum Inverter mit BS170( nach Anleitung [http://domoticx.com/p1-poort-slimme-meter-uitlezen-hardware/ ]) einen 1kOhm Wiederstand zwischen +5V und Data line setzen.
noiasca
December 12, 2021, 12:23pm
20
da wäre interessant
-ein vollständiger Sketch
-das konkrete Kriterium( kleiner -2.0) ????
-und entsprechende Mustermessages die etwas bewirken oder fehlerhaft nicht bewirken.
den lokal bei mir simuliert schaffe ich eine Abfrage auf < negativ
stiago2
December 12, 2021, 12:37pm
21
`#include <AltSoftSerial.h>
#define RX_PIN 8
#define TX_PIN 9
AltSoftSerial altSerial;
char c;
void setup() {
Serial.begin(115200);
Serial.println("\nStart");
//altSerial.begin(115200);
altSerial.begin(115200);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
}
void recvWithEndMarker(float &leistung) {
const byte maxChars = 32;
static char receivedChars[maxChars] = {'\0'};
static byte ndx = 0;
const char endMarker = '\n';
char rc;
if (altSerial.available()) {
c = altSerial.read();
c &= ~(1 << 10);
char inChar = (char)c;
Serial.print(c);
if (c != endMarker) {
if (ndx < maxChars - 1) {
receivedChars[ndx] = c;
ndx++;
receivedChars[ndx] = '\0';
}
} else {
//Serial.println(receivedChars);
if (!strncmp(receivedChars, "1-0:2.7.0(", 10))
{
char* zeigerKlammerAuf = strchr(receivedChars, '(');
leistung = strtod(zeigerKlammerAuf + 1, NULL); // stoppt automatisch beim *
}
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
}
}
}
void loop() {
float leistung = -1;
recvWithEndMarker(leistung);
if (leistung >= 0) {
Serial.print(F("Leistung = "));
Serial.println(leistung, 3);
}
if (leistung > 0.050) {
digitalWrite(3, LOW);
} else {
// turn LED off:
digitalWrite(3, HIGH);
}
}`
Relais bleibt angezogen bei Leistung 0.209 und 0.000