Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4578
Wohnort: Berlin
|
@sveni-lee: Nee das funktioniert immer noch nicht. Wenn, dann nur zufällig und wahrscheinlich auch nur einmal. Es hat sich seit dem ich angefangen habe diese Antwort zu schreiben zwar verbessert, aber nicht genug. Erklär mal wie Du auf die 50 kommst. Wenn es so funktionieren würde, dann ist Dir hoffentlich klar das in der Datei eine andere (kleinere) Zahl landen könnte als an den Server gesendet wird‽ Ich vermute mal das soll nicht so sein… In der Dokumentation zu curl_easy_init() sehe ich Sachen, die Du nicht berücksichtigt hast. Der letzte Satz im ersten Absatz der Beschreibung ist wichtig. Und auf Fehler testen ebenfalls. Ist jetzt nicht unbedingt ein Fehler, aber Netzwerkverbindungen können auch mal länger dauern oder hängen bleiben. Ist das okay das Dein Programm dann einfach so lange nichts in die Datei schreibt? Weisst Du ob die Plattform auf der das läuft garantiert, dass ein erhöhen einer int -Variable atomar ist? Ich glaube ich würde selbst wenn ich das wüsste, die entsprechenden kritischen Abschnitte schützen, oder das sehr deutlich in den Code schreiben, dass der nur dann funktioniert wenn das garantiert ist. Und zwar an allen Stellen die davon betroffen sind. wiringpi bietet für kritische Abschnitte auch Funktionen. Man mus bei C ja nicht mehr alle Variablen am Anfang eines Blocks deklarieren, aber man sollte trotzdem aufpassen, dass man Deklarationen und Code nicht so vermischt, dass es unübersichtlich wird. Also nicht error deklarieren und einen Wert zuweisen, dann zwei davon völlig unabhängige Deklarationen dazwischen schieben, und dann error auswerten. Ich würde das versenden des Wertes ins Netz ja in eine eigene Funktion schreiben. Dann kann man das auch unabhängig vom ganzen Rest entwickeln und testen. Ich kenne die curl_easy*-API nicht, aber ich vermute mal Du musst eine Rückruffunktion zum schreiben von Daten registrieren die die Daten dann einfach ignoriert, falls die sonst auf der Standardausgabe landen. Man kann das gleiche CURL* -Handle laut Dokumentation übrigens für mehrere aufeinanderfolgende curl_easy_perform() -Aufrufe verwenden. Man muss da nicht immer neue erstellen.
|
sveni-lee
(Themenstarter)
Anmeldungsdatum: 28. Mai 2013
Beiträge: 258
|
Marc_BlackJack_Rintsch schrieb: @sveni-lee: Nee das funktioniert immer noch nicht. Wenn, dann nur zufällig und wahrscheinlich auch nur einmal. Es hat sich seit dem ich angefangen habe diese Antwort zu schreiben zwar verbessert, aber nicht genug. Erklär mal wie Du auf die 50 kommst.
ich hatte gelesen, dass damit angegeben wird wieviele Zeichen das Array speichern kann
Wenn es so funktionieren würde, dann ist Dir hoffentlich klar das in der Datei eine andere (kleinere) Zahl landen könnte als an den Server gesendet wird‽ Ich vermute mal das soll nicht so sein…
nein ist es nicht
In der Dokumentation zu curl_easy_init() sehe ich Sachen, die Du nicht berücksichtigt hast. Der letzte Satz im ersten Absatz der Beschreibung ist wichtig. Und auf Fehler testen ebenfalls.
okay, das eine habe ich verstanden, der cleanup ist zwingend erforderlich.
Ist jetzt nicht unbedingt ein Fehler, aber Netzwerkverbindungen können auch mal länger dauern oder hängen bleiben. Ist das okay das Dein Programm dann einfach so lange nichts in die Datei schreibt?
nein, der zähler sollte dann schon weiter laufen...
Weisst Du ob die Plattform auf der das läuft garantiert, dass ein erhöhen einer int -Variable atomar ist? Ich glaube ich würde selbst wenn ich das wüsste, die entsprechenden kritischen Abschnitte schützen, oder das sehr deutlich in den Code schreiben, dass der nur dann funktioniert wenn das garantiert ist. Und zwar an allen Stellen die davon betroffen sind. wiringpi bietet für kritische Abschnitte auch Funktionen.
das verstehe ich nicht, der Abschnitt mit wiringpi ist aus dem example, welches bei dem Paket dabei war
Man mus bei C ja nicht mehr alle Variablen am Anfang eines Blocks deklarieren, aber man sollte trotzdem aufpassen, dass man Deklarationen und Code nicht so vermischt, dass es unübersichtlich wird. Also nicht error deklarieren und einen Wert zuweisen, dann zwei davon völlig unabhängige Deklarationen dazwischen schieben, und dann error auswerten.
Ich würde das versenden des Wertes ins Netz ja in eine eigene Funktion schreiben. Dann kann man das auch unabhängig vom ganzen Rest entwickeln und testen.
also so wie es bei der error abfrage gemacht wurde?
Ich kenne die curl_easy*-API nicht, aber ich vermute mal Du musst eine Rückruffunktion zum schreiben von Daten registrieren die die Daten dann einfach ignoriert, falls die sonst auf der Standardausgabe landen. Man kann das gleiche CURL* -Handle laut Dokumentation übrigens für mehrere aufeinanderfolgende curl_easy_perform() -Aufrufe verwenden. Man muss da nicht immer neue erstellen.
das verstehe ich auch wieder nicht
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Bevor man sich in die Untiefen der asynchronen Ausführung von Code begibt, könnte man sich auch überlegen, ob man nicht der Einfachheit halber den C-Teil so klein wie möglich hält - die Verarbeitung eines ermittelten Zählerwertes ist ja etwas, das man leicht in der Shell lösen kann, wenn man die Ausgabe des Programms auf stdout per Pipe weiterreicht.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 | #include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <wiringPi.h>
// What GPIO input are we using?
// This is a wiringPi pin number
#define BUTTON_PIN 9
// globalCounter:
// Global variable to count interrupts
// Should be declared volatile to make sure the compiler doesn't cache it.
static volatile int globalCounter = 0 ;
/*
* myInterrupt:
*********************************************************************************
*/
void myInterrupt (void)
{
++globalCounter ;
}
int parse_value_from_file(const char *filename, int *value)
{
FILE *fd = fopen(filename, "r");
if (fd == NULL) {
fprintf(stderr, "could not open %s\n", filename);
return 1;
}
int count = fscanf(fd, "%d", value);
fclose(fd);
if (count != 1) {
fprintf(stderr, "could not parse %s successfully\n", filename);
return 2;
}
return 0;
}
/*
*********************************************************************************
* main
*********************************************************************************
*/
int main (void)
{
const char filename[] = "/var/strom/stromzähler1";
int myCounter;
int error = parse_value_from_file(filename, &myCounter);
if (error) {
myCounter = 0;
fprintf(stderr, "unable to read initial value from %s, starting at %d", filename, myCounter);
}
globalCounter = myCounter;
if (wiringPiSetup () < 0)
{
fprintf (stderr, "Unable to setup wiringPi: %s\n", strerror (errno)) ;
return 1 ;
}
if (wiringPiISR (BUTTON_PIN, INT_EDGE_FALLING, &myInterrupt) < 0)
{
fprintf (stderr, "Unable to setup ISR: %s\n", strerror (errno)) ;
return 1 ;
}
for (;;)
{
fprintf(stderr, "Waiting ... ");
while (myCounter == globalCounter)
delay (100) ;
fprintf (stdout, "%d\n", globalCounter);
myCounter = globalCounter ;
}
return 0 ;
}
|
gpio_counter | while read -r value; do
echo "$value" > /var/strom/stromzähler1
curl "http://192.168.178.38:8082/set/javascript.0.Stromzähler.Normalstrom.Zählerstand_input?value=${value}"
done
Dann wäre das schlimmste, was einem passieren könnte, dass man nicht jede Werteveränderung sieht, aber da die zeitliche Auflösung anscheinend nicht besonders kritisch ist (der Delay wartet ja auch schon 100 ms) sollte das für eine Stromzähler vermutlich völlig ausreichend sein.
|
sveni-lee
(Themenstarter)
Anmeldungsdatum: 28. Mai 2013
Beiträge: 258
|
für mich zum besseren Verständnis. das schreiben der in die Datei übernimmt jetzt
| echo "$value" > /var/strom/stromzähler1
|
richtig? und danach wird der Wert dann übertragen... den zweiten Teil packe ich dann in ein Bash script? das bedeutet, dass das zweite skript immer vor dem ersten gestartet sein muß, damit der Wert auch korrekt hoch gesetzt wird... aber woher kommt gpio_counter ?
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
sveni-lee schrieb: für mich zum besseren Verständnis. das schreiben der in die Datei übernimmt jetzt
| echo "$value" > /var/strom/stromzähler1
|
richtig? und danach wird der Wert dann übertragen...
Ja, in der Schleife kannst du mit der Zahl, die das Programm, das die GPIO-Interrupts zählt und dann auf stdout ausgibt, bequem weiterarbeiten. Das ist natürlich nicht so effizient wie wenn man das komplett in C schreiben würde, aber dafür vermutlich deutlich weniger Aufwand für dich... den zweiten Teil packe ich dann in ein Bash script?
Es darf auch ein Skript für andere Shell sein, in der read verfügbar ist. das bedeutet, dass das zweite skript immer vor dem ersten gestartet sein muß, damit der Wert auch korrekt hoch gesetzt wird... aber woher kommt gpio_counter ?
gpio_counter ist das in C geschriebene Programm. Wenn es nicht im PATH ist, muss man es natürlich mit einem passenden Pfad aufrufen.
|
sveni-lee
(Themenstarter)
Anmeldungsdatum: 28. Mai 2013
Beiträge: 258
|
klappt leider so nicht... was geht:
| #!/bin/bash
COUNTER=$(cat /var/strom/stromcounter1)
curl http://192.168.1.142:8082/set/javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input?value={$COUNTER}
|
was nicht klappt: | #!/bin/bash
/home/strompi/WiringOP-Zero/examples/test3 | while read -r counter; do
curl http://192.168.1.142:8082/set/javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input?value={counter}
done
|
ich weiß nicht so recht wo der unterschied liegt...
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Die Variable counter wird in der URL nicht ersetzt, wenn du kein Dollar-Zeichen davor stellst - und du solltest den String quoten.
Wie muss die URL denn aussehen?
http://192.168.1.142:8082/set/javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input?value={1}
oder
http://192.168.1.142:8082/set/javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input?value=1 ?
|
sveni-lee
(Themenstarter)
Anmeldungsdatum: 28. Mai 2013
Beiträge: 258
|
es gehen beide varianten auf Komandozeilen Ebene | strompi@strompi:~$ curl http://192.168.1.142:8082/set/javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input?value={1}
{"id":"javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input","value":1,"val":1}strompi@strompi:~$
strompi@strompi:~$ curl http://192.168.1.142:8082/set/javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input?value=1
{"id":"javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input","value":1,"val":1}strompi@strompi:~$
strompi@strompi:~$
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Und was genau funktioniert an der Variante, die ich oben gepostet hatte nicht? So kannst du sehen, was die Shell daraus macht:
| #!/bin/bash
/home/strompi/WiringOP-Zero/examples/test3 | while read -r counter; do
echo "http://192.168.1.142:8082/set/javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input?value=${counter}"
curl "http://192.168.1.142:8082/set/javascript.0.Stromzaehler.Normalstrom.Zaehlerstand_input?value=${counter}"
done
|
|
sveni-lee
(Themenstarter)
Anmeldungsdatum: 28. Mai 2013
Beiträge: 258
|
es gibt gar nichts aus... das C-Program läuft aber | strompi@strompi:~/WiringOP-Zero/examples$ sudo /home/strompi/WiringOP-Zero/examples/test3
436
437
438
439
440
441
442
443
|
| strompi@strompi:~$ sudo ./stromexport.sh
[sudo] password for strompi:
|
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4578
Wohnort: Berlin
|
Ich vermute mal da fehlt ein fflush() im C-Programm wenn man nicht möchte das die Ausgaben gepuffert werden.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Ok, dann muss man das vermutlich nach Zeile 85 einfügen:
|
sveni-lee
(Themenstarter)
Anmeldungsdatum: 28. Mai 2013
Beiträge: 258
|
ja also... das funktioniert jetzt mit der Übertragung schon mal ABER die beiden Skripte laufen asynchron. die übergebenen Werte passen nicht zusammen...
okay, habs rausgefunden fflush(stdout) muss hinter fprintf (stdout, "%d\n", globalCounter); stehen. Das zweite was ich rausgefunden habe mit dem Bash-Skript wird das C-Programm automatisch gestartet...was schon mal super ist... der export an Simple-API funktioniert so auch... jetzt müsste das Bash-Skript noch in den Autostart
ich dachte an so etwas:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | #! /bin/sh
# Aktionen
case "$1" in
start)
./usr/local/bin/stromexport.sh &
# /opt/beispiel start
;;
stop)
killall stromexport.sh
# /opt/beispiel stop
;;
restart)
killall stromexport.sh
./usr/local/bin/stromexport.sh &
# /opt/beispiel restart
;;
esac
exit 0
|
und das ganze in die /etc/init.d/stromexport packen
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Ubuntu 16.04 bringt Systemd als Init-System mit - du könntest z.B. eine /etc/systemd/system/electric-meter.service anlegen: | [Unit]
Description=electric meter
After=network-online.target
[Service]
ExecStart=/usr/local/bin/stromexport.sh
[Install]
WantedBy=multi-user.target
|
Und die dann mit diesen Befehlen aktiveren bzw. starten:
sudo systemctl daemon-reload # immer nach Änderungen an der service-Datei ausführen, damit Systemd die neu einliest
sudo systemctl enable electric-meter.service # damit der Dienst beim Booten gestartet wird
sudo systemctl start electric-meter.service # startet den Dienst sofort network-online.target hängt von der Methode zur Netzwerkkonfiguration ab - falls das nicht wie erwartet funktionieren sollte, zeig mal bitte die Ausgabe von
systemctl is-enabled NetworkManager-wait-online.service
systemctl is-enabled systemd-networkd-wait-online.service da müsstest du ggf. noch den passenden Dienst aktivieren.
|
sveni-lee
(Themenstarter)
Anmeldungsdatum: 28. Mai 2013
Beiträge: 258
|
was soll ich sagen, klappt genau so wie es soll... Vielen Dankk für Deine Mühe und vor allem für deine Geduld! Ich lasse den globalCounter zusätzlich noch in die Datei schreiben. Sollte das Frontend (iobroker) mal abgeschaltet werden, werden die Werte trotzdem noch weiter gesammelt. Und ein zweiter Vorteil, ich kann in der Datei /var/strom/stromcounter1 auch noch händisch korrekturen vornehmen...
|