[Linux] seriele communicatie met router

Pagina: 1
Acties:
  • 521 views sinds 30-01-2008
  • Reageer

  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Ik ben bezig met een projectje, namelijk om de opbrengstgegevens uit mijn solar omvormer automatisch in te lezen. Deze omvormer heeft een seriele poort, en is aangesloten op een Asus Wl500g router, waar een seriele poort op gemod is. Op deze router draait de zgn OLEG firmware, linux dus. Ik heb een programmaatje draaien (ser2net) waarmee ik seriele communicatie over tcp krijg, en op mijn pc kan ik netjes de data uitlezen.
Het is echter de bedoeling om de data binnen de router al uit te lezen, om deze dan later te verwerken oid. (bv met RRDtool om grafiekjes te maken oid)

Nu ben ik niet zo'n held in het zelf bedenken van scripts, dus heb ik gezocht naar een simpel scriptje waar ik het juiste commando kan versturen, zodat de solaromvormer zijn data terugstuurt.

Veel voorbeelden gaan echter uit van Perl, met SerialPort Device. Ik heb wel een perl variant (microperl) package op mijn router geïnstalleerd, maar die kan niet goed overweg met de scripts die ik op internet gevonden heb. Ik krijg allemaal foutmeldingen.

Het instellen van de baudrate etc lukt me nog wel.
Ik heb echter geen idee hoe ik een scriptje in elkaar zet waarmee ik wat hex waarden kan versturen, en het antwoord daarna uitleest, wat ik dan middels cron kan schedulen.
Wie geeft me een zetje in de goede richting?

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Boudewijn
  • Registratie: Februari 2004
  • Niet online

Boudewijn

omdat het kan

gewoon een simpel C progje schrijven?
bash? gewoon de meuk naar een tty pipen?

Zaram module kopen voor je glasvezelaansluiting?


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Ik ben inmiddels een stuk verder. Ik heb het volgende perl scriptje gemaakt/gejat:
code:
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
#!/opt/bin/microperl

# Serial port
$port = "/dev/tts/1";
#configure serial port for communication with Soladin
system("stty 9600 -crtscts < $port");
#open commandfile
open(INFILE, "/opt/tmp/receive") or die "can't find file";
#open outputfile
open (OUTFILE, ">/opt/tmp/output");
#open serial port
open(SERPORT,"+>$port") or die "can't open serial port";
#get command from commandfile (commands are 9 bytes long)
read (INFILE,$command,9);

#write command to serial (in fact to soladin)
print (SERPORT $command);

#read output from soladin (we expect 31 bytes)
read (SERPORT,$out,31);

#write result to output file
print OUTFILE $out;

close (SERPORT);
close (INFILE);
close (OUTFILE);


en dit stukje code schrijft de output in de file "output". Probleem hierbij is dat er geen communicatie mogelijk is in het donker. En dus blijft het script hangen op het read commando. Ik heb dit geprobeerd op te lossen met ALARM, maar dit schijnt niet te kunnen in microperl.
Iemand daar nog een ideetje over?

Als dit opgelost is, kan ik eindelijk verder met het uit elkaar trekken van de resultaatwaarden, (met unpack of zo) en dan het converteren naar de juiste waarden...

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • SA007
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:15

SA007

Moderator Tweaking
Deze code kan heel simpel vertaald worden naar een andere progtaal, heb je bash daar?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

# Serial port
PORT=/dev/tts/1
#configure serial port for communication with Soladin
stty 9600 -crtscts $PORT

#set commandfile
CMDFILE=/opt/tmp/receive
#set outputfile
OUTFILE=/opt/tmp/output

#get command from commandfile (commands are 9 bytes long)
CMD=`head -c 9 $CMDFILE`

#write command to serial (in fact to soladin)
echo -n $CMD > $PORT

#read output from soladin (we expect 31 bytes)
OUTPUT=`head -c 31 $PORT`

#write result to output file
echo $OUTPUT > $OUTFILE

  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
SA007 schreef op dinsdag 20 februari 2007 @ 18:50:
Deze code kan heel simpel vertaald worden naar een andere progtaal, heb je bash daar?
Ja, net geïnstalleerd ;)
Lijkt erop dat ie het ook wel doet, alleen schijnt momenteel de zon niet, dus ik krijg uiteraard geen data terug, en hij staat nu te wachten op data. Ik ga eens kijken wat ik in bash kan doen. Heb je toevallig ook een idee hoe ik een timeout kan maken?

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • SA007
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:15

SA007

Moderator Tweaking
Je kan met een combo van kill/sleep en background tasks wel wat leuke dingen doen..

Voorbeeld:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash

# Wacht een random tijd tussen de 0 en 10 sec,
# de & duwd het naar de background
sleep $[$RANDOM % 10]&

#sla het processid op en laat het ff zien
PID=$!
echo Proces gestart met pid $PID.

#wacht de timeout
sleep 5

#als het process nog draait, sluit het af
if [ -d /proc/$PID ]
then
  echo Hij draait nog, afsluiten.
  kill $PID
else
  echo Hij is afgesloten.
fi

  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

Uit de bash manual
code:
1
2
3
4
5
6
7
 TMOUT  If set to a value greater than zero, TMOUT  is  treated  as  the
              default timeout for the read builtin.  The select command termi-
              nates if input does not arrive after TMOUT seconds when input is
              coming  from  a terminal.  In an interactive shell, the value is
              interpreted as the number of seconds to  wait  for  input  after
              issuing  the  primary prompt.  Bash terminates after waiting for
              that number of seconds if input does not arrive


Als het procces hangt op de buildin 'read' command dan kan je dus de TMOUT variable zetten met het maximale aantal seconden dat je wilt wachten op antwoord.

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
SA007 schreef op dinsdag 20 februari 2007 @ 18:50:
Deze code kan heel simpel vertaald worden naar een andere progtaal, heb je bash daar?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

# Serial port
PORT=/dev/tts/1
#configure serial port for communication with Soladin
stty 9600 -crtscts $PORT

#set commandfile
CMDFILE=/opt/tmp/receive
#set outputfile
OUTFILE=/opt/tmp/output

#get command from commandfile (commands are 9 bytes long)
CMD=`head -c 9 $CMDFILE`

#write command to serial (in fact to soladin)
echo -n $CMD > $PORT

#read output from soladin (we expect 31 bytes)
OUTPUT=`head -c 31 $PORT`

#write result to output file
echo $OUTPUT > $OUTFILE
Hmmmz, nu het eenmaal weer licht is, en de panelen weer draaien, blijkt toch dat het niet werkt. Waarschijnlijk omdat de commando's en de output allemaal hex waarden zijn, en head en echo interpreteren dit niet als zodanig denk ik.

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • sam.vimes
  • Registratie: Januari 2007
  • Laatst online: 07-01 22:10
Voor het afbreken van een willekeurig "hangend" commando na een bepaalde tijd kun je "timeout" gebruiken.
code:
1
timeout 20 head $CMDFILE
omdat de commando's en de output allemaal hex waarden zijn
Voor vertalen van ascii hex naar binair en terug kun je denk ik het eenvoudigst de pack en unpack functies van Perl gebruiken, maar ik weet niet of microperl die ook ondersteunt.

  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
sam.vimes schreef op woensdag 21 februari 2007 @ 10:15:
Voor het afbreken van een willekeurig "hangend" commando na een bepaalde tijd kun je "timeout" gebruiken.
code:
1
timeout 20 head $CMDFILE



[...]


Voor vertalen van ascii hex naar binair en terug kun je denk ik het eenvoudigst de pack en unpack functies van Perl gebruiken, maar ik weet niet of microperl die ook ondersteunt.
Dat timeout commando zou geweldig zijn, maar ik heb niet het idee dat bash of perl dit op deze manier kent. Onder perl zou ik met alarms moeten werken als ik het goed begrepen heb, maar dat werkt niet in microperl.

Over de hex waarden; mijn perl scriptje haalt de juiste string wel op, het achteraf vertalen naar juiste waarden komt nog wel.

Het probleem waar ik nu op doel is dat het Bash script van SA007 niet werkt. Terwijl het perl script wel goed gaat. En ogenschijnlijk gebeurt er hetzelfde. En ik heb het gevoel dat het aan die hex waarden ligt.
Het lijkt erop dat de inverter de data al terug heeft gestuurd, voordat het uitlezen plaats vind. Zodoende staat ie te wachten maar komt er nix meer. Daarnaast, het lijkt wel zo te zijn dat head alleen karakters inleest, de nullen komen niet aan. En die heb ik wel nodig...

[ Voor 12% gewijzigd door Mistraller op 21-02-2007 11:36 ]

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

Je kunt dit kunnen proberen:
code:
1
2
3
4
5
6
7
8
9
10
OUTPUT='Zon is uit'

get_data () {
      #write command to serial (in fact to soladin)
      echo -n $CMD > $PORT
      # read the answer from redirected stdin
      read -t10 -n31 OUTPUT
}

get_data < $PORT


Dit opent de serial port voordat CMD wordt weggeschreven dus het antwoord zou dan in de buffer moeten blijven staan.
De builtin read heeft een timeout optie -t al weet ik niet of die werkt voor een serial port, volgens de manpage werkt het alleen bij een terminal of pipe.

PS: 'echo -n $CMD' onderdrukt de newline, is dat de bedoeling?

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Buffy schreef op woensdag 21 februari 2007 @ 12:51:
Je kunt dit kunnen proberen:
code:
1
2
3
4
5
6
7
8
9
10
OUTPUT='Zon is uit'

get_data () {
      #write command to serial (in fact to soladin)
      echo -n $CMD > $PORT
      # read the answer from redirected stdin
      read -t10 -n31 OUTPUT
}

get_data < $PORT


Dit opent de serial port voordat CMD wordt weggeschreven dus het antwoord zou dan in de buffer moeten blijven staan.
De builtin read heeft een timeout optie -t al weet ik niet of die werkt voor een serial port, volgens de manpage werkt het alleen bij een terminal of pipe.

PS: 'echo -n $CMD' onderdrukt de newline, is dat de bedoeling?
Ik heb aan de andere kant van de kabel even een laptopje gehangen om te kunnen zien wat er nu daadwerkelijk over het lijntje gaat.
Met het read commando krijg ik geen bruikbare data terug, maar de timeout werkt wel!
Het volgende werkt overigens wel, maar dan dus weer zonder timeout:
code:
1
2
3
4
5
6
7
8
9
10
#!/opt/bin/bash

PORT=/dev/tts/1
CMD=/opt/tmp/receive

get_data () {
  cat $CMD > $PORT
  dd if=$PORT of=/opt/tmp/output bs=31 count=1
}
get_data < $PORT


Voor de beeldvorming;
het bestand "receive" bevat slechts deze hex waarden: 11 00 00 00 B6 00 00 00 C7 en die moet in zijn geheel verstuurd worden.
De ontvangst die ik verwacht moet er ongeveer zo uit zien:
00 00 11 00 B6 F3 00 00 C5 03 59 00 8A 13 DF 00 00 00 4C 00 3A 10 00 2E 9F 5D 00 00 00 00 17

De betekenis van deze data is als volgt:

00 00 11 00 B6 F3 00 00: header met daarin het commando B6
C5 03 : 0x03C5 hex = 965 decimaal = 96.5 Volt spanning van panelen
59 00 : 0x0059 hex = 89 decimaal = 0.89 Amp stroom uit panelen
8A 13 : 0x138A hex = 5002 decimaal = 50.02 Hz
DF 00 : 0x00DF hex = 223 decimaal = 223 Volt
00 00
4C 00 : 0x004C hex = 76 decimaal = 76 Watt vermogen
3A 10 : 0x103A hex = 4154 decimaal = 41.54 Kwh totaal al geleverd
00 2E : 0x002E hex = 46 decimaal = 46 graden (temperatuur)
9F 5D 00 00 00 00 : 0x5D9F hex = 23967 decimaal = aantal minuten werkzaam = 399:27 Uur (nu dus 16dagen)

17 (checksum)

Dit checksum wil ik gebruiken om de ontvangen string te controleren. Het is namelijk de uitkomst van de optelling van alle bytes.

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

Even voor de duidelijkheid, met hex waarden bedoel je dus binaire waarden en niet een string met hex getalllen?

Dat gaat inderdaad niet werken mbv 'read' en 'head' aangezien die strings lezen en dus afkappen bij een '\0' of '\n' waarde.
Het commando 'dd' heeft daar geen moeite mee maar het gebruik van de if= optie maakt de functie met redirect dus overbodig :)

dd heeft overigens een 'nonblock' optie misschien is dat wat.

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Buffy schreef op woensdag 21 februari 2007 @ 14:51:
Even voor de duidelijkheid, met hex waarden bedoel je dus binaire waarden en niet een string met hex getalllen?

Dat gaat inderdaad niet werken mbv 'read' en 'head' aangezien die strings lezen en dus afkappen bij een '\0' of '\n' waarde.
Het commando 'dd' heeft daar geen moeite mee maar het gebruik van de if= optie maakt de functie met redirect dus overbodig :)

dd heeft overigens een 'nonblock' optie misschien is dat wat.
Dat nonblock is ergens anders voor, maar met de eerder genoemde optie heb ik het voor mekaar gekregen. Na vele tutorials, examples, man pages etc etc ben ik én veel wijzer geworden in linux én heb ik het volgende scriptroutines gebrouwen:

code:
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
PORT=/dev/tts/1
CMD=/opt/tmp/receive
OUT=/opt/tmp/output
ZERO=/opt/tmp/zero
LOG=/opt/tmp/soladin.log

get_data(){
cat $CMD > $PORT
dd if=$PORT of=$OUT bs=31 count=1 2>/dev/null &
PID=$!
sleep 3
if [ -d /proc/$PID ]
then
  rcvd="no"
  cp $ZERO $OUT
  echo `date`":   No reaction from soladin comport" >> $LOG
  kill $PID
else
  rcvd="yes"
fi
}

chk_data () {
count=0
check=0
while [ $count -lt 30 ];do
let check=check+0x`dd if=$OUT count=1 bs=1 skip=$count 2>/dev/null|od -H -v|head -c 24|tail -c 2`
let count=count+1
done
if [ "`printf "%02X" $check|tail -c 2`" = "`dd if=$OUT count=1 bs=1 skip=30 2>/dev/null|od -H -v|head -c 24|tail -c 2|tr a-f A-F`" ]; then
 rcvd="chk"
else
 rcvd="nochk"
 echo `date`":   Checksum error in received data" >> $LOG
fi
}


Deze werken perfect! Het script is niet zo snel, mede door de trage processor in de router wellicht, maar dat boeit niet zo. Ik heb mijn data, en de verwerking is ook al een heel eind.
Bedankt allemaal voor het meedenken in elk geval!

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

Je hoeft natuurlijk niet 31 keer de transformatie van byte naar string uit te voeren.
Het onderstaande code roept maar een keer 'od' aan en gebruikt daarna alleen
buildin arithmetic om de checksum te controleren.

code:
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
chk_data () {
   let count=0
   for i in `od -t x1 -w31 -v < $OUT | head -n 1 | sed -e 's/^0*[ ]//g'` ; do
       data[$count]="0x$i"
       (( count += 1 ))
   done
   if [ $count -ne 31 ]; then
      rcvd="nochk"
      echo `date`":  Wrong amount of data received" >> $LOG
   else
      let sum=0
      for ((i=0; i < 30; i++)); do
           (( sum += data[i] ))
      done

      if (( sum%256 == data[30] )); then
         rcvd="chk"
         echo `date`":   Checksum ok" >> $LOG
      else
         rcvd="nochk"
         echo `date`":   Checksum error in received data" >> $LOG
      fi
   fi
}

[/] <- nogdig vanwege een react parse bugje????


PS: Als de router's bash versie geen array's ondersteunt dan kan je de sommatie in de eerste for lus uitvoeren. Maar dan moet je natuurlijk wel de laatste waarde (checksum) onthouden en voor de test er weer aftrekken :)

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Array's gaat wel goed, echter; 'od' kent bij mij niet al de opties die je gebruikt. (Vandaar ook dat head en tail gepruts.) Wat sed precies doet in je voorbeeld volg ik ook niet helemaal.
Ik heb overigens het gevoel dat ik bij het inlezen van de data de array al zou kunnen vullen.

PS ik heb je een DM gestuurd.

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

MisTraller schreef op vrijdag 23 februari 2007 @ 12:15:
Array's gaat wel goed, echter; 'od' kent bij mij niet al de opties die je gebruikt. (Vandaar ook dat head en tail gepruts.) Wat sed precies doet in je voorbeeld volg ik ook niet helemaal.
Ik heb overigens het gevoel dat ik bij het inlezen van de data de array al zou kunnen vullen.

PS ik heb je een DM gestuurd.
Als jouw 'od' de optie '-t u1' ondersteund kan je inderdaad direct de array assignen:

code:
1
data=(`od -t u1 -v < $OUT | sed -e 's/^[0-9]*//g'`)


Het 'sed' commando is nodig om de file offset waarde aan het begin van de regels weg te krijgen. Als jouw 'od' het argument '-w31' ondersteund dan kan je het 'sed' commando weglaten maar dan staan de waarden in de array elementen 1 t/m 31 ipv van 0 t/m 30.

Het script wordt dan:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data=(`od -t u1 -v -w31 < $OUT`)
if [ ${#data[@]} -ne 33 ]; then  # [0] and [32] are file offsets
   rcvd="nochk"
   echo `date`":  Wrong amount of data received" >> $LOG   echo "fout"
else
   sumstr="${data[@]:1:30}"
   let sum=${sumstr// /+}
   if ((sum%256 == data[31])); then
      rcvd="chk"
      echo `date`":   Checksum ok" >> $LOG
   else
      rcvd="nochk"
      echo `date`":   Checksum error in received data" >> $LOG
   fi
fi


Mocht jouw 'od' niet de '-w' en de '-t' opties ondersteunen dan hopelijk wel de traditionele '-b' optie die octal bytes geeft. Je moet dan nog wel een 0 voor de waarden plakken zodat bash ze als octal herkent.

Dat kan met een extra 'sed' commando:
code:
1
data=(`od -b -v < $OUT | sed -e 's/^[0-9]*//g' | sed -e 's/[ ]\([0-9]\)/ 0\1/g'`)


of met een for lusje:
code:
1
2
3
for ((i = 0; i < 31; i++)); do
   let data[$i]=0${data[$i]}  # let zorgt voor transformatie octal -> decimal
done


of met string substitutie:
code:
1
2
(( sum=0${data[@]/#/+0}${data[30]/#/-0} ))
if (( sum%256 == ${data[30]/#/0} )); then



Perl eat your heart out :)


PS: Dit is een handige site voor allerlei bash scripting technieken: Advanced Bash-Scripting Guide

[ Voor 3% gewijzigd door Buffy op 23-02-2007 16:18 ]

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Buffy schreef op vrijdag 23 februari 2007 @ 16:02:
[...]


Als jouw 'od' de optie '-t u1' ondersteund kan je inderdaad direct de array assignen:

code:
1
data=(`od -t u1 -v < $OUT | sed -e 's/^[0-9]*//g'`)


Het 'sed' commando is nodig om de file offset waarde aan het begin van de regels weg te krijgen. Als jouw 'od' het argument '-w31' ondersteund dan kan je het 'sed' commando weglaten maar dan staan de waarden in de array elementen 1 t/m 31 ipv van 0 t/m 30.

Het script wordt dan:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data=(`od -t u1 -v -w31 < $OUT`)
if [ ${#data[@]} -ne 33 ]; then  # [0] and [32] are file offsets
   rcvd="nochk"
   echo `date`":  Wrong amount of data received" >> $LOG   echo "fout"
else
   sumstr="${data[@]:1:30}"
   let sum=${sumstr// /+}
   if ((sum%256 == data[31])); then
      rcvd="chk"
      echo `date`":   Checksum ok" >> $LOG
   else
      rcvd="nochk"
      echo `date`":   Checksum error in received data" >> $LOG
   fi
fi


Mocht jouw 'od' niet de '-w' en de '-t' opties ondersteunen dan hopelijk wel de traditionele '-b' optie die octal bytes geeft. Je moet dan nog wel een 0 voor de waarden plakken zodat bash ze als octal herkent.

Dat kan met een extra 'sed' commando:
code:
1
data=(`od -b -v < $OUT | sed -e 's/^[0-9]*//g' | sed -e 's/[ ]\([0-9]\)/ 0\1/g'`)


of met een for lusje:
code:
1
2
3
for ((i = 0; i < 31; i++)); do
   let data[$i]=0${data[$i]}  # let zorgt voor transformatie octal -> decimal
done


of met string substitutie:
code:
1
2
(( sum=0${data[@]/#/+0}${data[30]/#/-0} ))
if (( sum%256 == ${data[30]/#/0} )); then



Perl eat your heart out :)


PS: Dit is een handige site voor allerlei bash scripting technieken: Advanced Bash-Scripting Guide
od geeft bij mij als opties:
[mistral@router tmp]$ od -t u1 output
od: illegal option -- t
BusyBox v1.1.3 (2006.06.29-17:07+0000) multi-call binary

Usage: od [-aBbcDdeFfHhIiLlOovXx] [FILE]

-b kan dus wel.

bv output is gevuld met:
00 00 11 00 B6 F3 00 00 9B 02 A0 00 8A 13 DB 00
00 00 64 00 48 07 00 3B 97 73 00 00 00 00 67

echo `od -b -v < output | sed -e 's/^[0-9]*//g' | sed -e 's/[ ]\([0-9]\)/ 0\1/g'`
geeft:

0000 0000 0021 0000 0266 0363 0000 0000 0233 0002 0240 0000 0212 0023 0333 0000 0000 0000 0144 0000 0110 0007 0000 0073 0227 0163 0000 0000 0000 0000 0147

Het lastige is dat er dus naderhand ook nog een conversie plaats moet vinden vanuit de data.

Ik moet bv om het voltage visueel te krijgen het volgende doen;
In de uitlezing: byte 9 =85 en byte 10 = 02
ik plak dan byte 9 achter byte 10 zodat het 0285 wordt en dat converteer ik(met let, dat had ik reeds gevonden) naar decimaal. Dan komt er 645 uit.
Dit deel ik (in een andere routine) door 10 met expr, plak er een komma achter, plak er (met tail -c 1) het cijfer 5 achter en een V.
En dan heb ik dus 64,5V.
code:
1
let Usol=0x`dd if=output count=1 bs=1 skip=9 2>/dev/null|od -H -v|head -c 24|tail -c 2``dd if=output count=1 bs=1 skip=8 2>/dev/null|od -H -v|head -c 24|tail -c 2`

code:
1
echo -n "<TR><TD>"`expr $Usol \/ 10`","`echo -n $Usol|tail -c 1`" V</TD><TD>Spanning Solarpanelen</TD></TR>" >> index.html.tmp

Het omvormen en wegschrijven doe ik liefst in 2 stukken, want ik weet al dat RRDTOOL niet met komma's overweg kan. Maar ik heb daar nog niet uitgebreid naar gekeken.

Het script werkt overigens nu helemaal, en met alle dd commando's (die ik uiteraard in het bovenste stuk wéér gebruik ;)) duurt het 12 seconden als alles in een keer goed loopt. Waarbij de sleep bij het inlezen van de compoort op 2 staat. Dat moet veel sneller kunnen op jouw manier, daar ben ik van overtuigd.

Het was overigens 20 seconden, maar dat had een hele andere oorzaak, de webcam software van die router is brak en bleek 95% cpu te pakken. (Dus dat is nu ook een sideproject om iets anders te vinden)

data is te vinden op http://mystery.reinieren.net/solar

[ Voor 7% gewijzigd door Mistraller op 24-02-2007 01:41 ]

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

MisTraller schreef op zaterdag 24 februari 2007 @ 01:32:
[...]

od geeft bij mij als opties:
[mistral@router tmp]$ od -t u1 output
od: illegal option -- t
BusyBox v1.1.3 (2006.06.29-17:07+0000) multi-call binary

Usage: od [-aBbcDdeFfHhIiLlOovXx] [FILE]

-b kan dus wel.

bv output is gevuld met:
00 00 11 00 B6 F3 00 00 9B 02 A0 00 8A 13 DB 00
00 00 64 00 48 07 00 3B 97 73 00 00 00 00 67

echo `od -b -v < output | sed -e 's/^[0-9]*//g' | sed -e 's/[ ]\([0-9]\)/ 0\1/g'`
geeft:

0000 0000 0021 0000 0266 0363 0000 0000 0233 0002 0240 0000 0212 0023 0333 0000 0000 0000 0144 0000 0110 0007 0000 0073 0227 0163 0000 0000 0000 0000 0147

Het lastige is dat er dus naderhand ook nog een conversie plaats moet vinden vanuit de data.

Ik moet bv om het voltage visueel te krijgen het volgende doen;
In de uitlezing: byte 9 =85 en byte 10 = 02
ik plak dan byte 9 achter byte 10 zodat het 0285 wordt en dat converteer ik(met let, dat had ik reeds gevonden) naar decimaal. Dan komt er 645 uit.
Dit deel ik (in een andere routine) door 10 met expr, plak er een komma achter, plak er (met tail -c 1) het cijfer 5 achter en een V.
En dan heb ik dus 64,5V.
code:
1
let Usol=0x`dd if=output count=1 bs=1 skip=9 2>/dev/null|od -H -v|head -c 24|tail -c 2``dd if=output count=1 bs=1 skip=8 2>/dev/null|od -H -v|head -c 24|tail -c 2`

code:
1
echo -n "<TR><TD>"`expr $Usol \/ 10`","`echo -n $Usol|tail -c 1`" V</TD><TD>Spanning Solarpanelen</TD></TR>" >> index.html.tmp
Auw dat doet gewoon pijn aan mijn ogen.
Als je de data in een array hebt staan dan is het natuurlijk efficienter om die bij het omvormen te gebruiken (het maakt niet uit of die in octal notatie staan zolang er maar een voorloop 0 aanzit).

Jouw voorbeeld wordt dan:

code:
1
(( Usol = data[9] * 256 + data[8] ))  # denk aan nul offset van de array


Voor uitvoer zou ik ook de buildin string operaties van bash gebruiken:

code:
1
2
3
4
5
6
7
print_float () {
   let decval=$2 # evetuele conversie
   let l=${#decval}-$1
   echo ${decval:0:$l},${decval:$l:$1}
}

print_float 1 $Usol


Zie de Bash HOWTO voor meer uitleg over de string operaties

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Buffy schreef op zaterdag 24 februari 2007 @ 03:19:
[...]


Auw dat doet gewoon pijn aan mijn ogen.
Ook aan mijn ogen ;)

Het is nu nog een draak van een script, maar dat gaat goed komen denk ik. Ik ga komende week eens hard met die arrays aan de slag want ik zie daar zeker de voordelen van in.
Ik kan zeker verder met je aanwijzingen!

Ben ff met die webcam software bezig geweest, daar ga ik palantir voor gebruiken.
Want uiteindelijk moet het een pagina worden waar naast de waarden, grafieken en cijfertjes, ook gewoon te zien is dat de zon schijnt...

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Zo, ben d'r weer even ingedoken; en het scheelt een slok op een borrel!
De tijdsduur van het totale script (zonder echt uitlezen van de panelen want dat kan ik pas morgen weer testen) is nu minder dan 1 seconde of zo.
Ik kon je code bijna ongewijzigd gebruiken :+

Een stukje ging hardnekkig fout; dat heb ik zo opgelost:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
print_float () {
   let decval=$2
   if [ ${#decval} -gt $1 ]; then
     let l=${#decval}-$1
     echo ${decval:0:$l},${decval:$l:$1}
   else
      if [ ${#decval} -lt $1 ]; then
       echo 0,0$decval
      else 
       echo 0,$decval
      fi
   fi
}

Er komt nogal eens een waarde van 0,35 of 0,05 uit (of 0) en nu gaat het daar niet op fout.

Ik kon niet zo snel bedenken hoe ik dit korter kan krijgen. Al is het nu ook niet echt helemaal kloppend voor de conversies met 1 getal achter de komma. Maar in mijn geval kan dat niet voorkomen volgens mij.

Wat ook nog een hardnekkig probleempje is;
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
get_data(){
cat $CMD > $PORT
dd if=$PORT of=$OUT bs=1 count=31 2>/dev/null &
PID=$!
sleep 2
if [ -d /proc/$PID ]
then
  rcvd="no"
  cp $ZERO $OUT
  echo `date -R`":   No reaction from soladin comport" >> $LOG
  kill $PID
else
  rcvd="yes"
fi
}

Als het script uit de routine komt (en er is geen daglicht), krijg ik bijna altijd
./getdata.sh: line 87: 4140 Terminated dd if=$PORT of=$OUT bs=1 count=31 2> /dev/null
Ik heb >/dev/null overal al gehad, maar ik krijg deze niet onderdrukt. Al komt het ook soms voor dat het helemaal niet optreedt.
In het voorbeeld wat SA007 gaf, krijg ik die melding helemaal niet.
Volgens mij heb ik er geen last van zodra het script als cron job gaat draaien, maar netjes vind ik het niet.
ook met
code:
1
2
if [ -n "`pidof dd`" ]; then
 killall dd 2>/dev/null

krijg ik de melding.

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

MisTraller schreef op maandag 26 februari 2007 @ 19:58:
Zo, ben d'r weer even ingedoken; en het scheelt een slok op een borrel!
De tijdsduur van het totale script (zonder echt uitlezen van de panelen want dat kan ik pas morgen weer testen) is nu minder dan 1 seconde of zo.
Ik kon je code bijna ongewijzigd gebruiken :+

Een stukje ging hardnekkig fout; dat heb ik zo opgelost:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
print_float () {
   let decval=$2
   if [ ${#decval} -gt $1 ]; then
     let l=${#decval}-$1
     echo ${decval:0:$l},${decval:$l:$1}
   else
      if [ ${#decval} -lt $1 ]; then
       echo 0,0$decval
      else 
       echo 0,$decval
      fi
   fi
}

Er komt nogal eens een waarde van 0,35 of 0,05 uit (of 0) en nu gaat het daar niet op fout.

Ik kon niet zo snel bedenken hoe ik dit korter kan krijgen. Al is het nu ook niet echt helemaal kloppend voor de conversies met 1 getal achter de komma. Maar in mijn geval kan dat niet voorkomen volgens mij.
Oeps, getallen kleiner dan nul, niet aan gedacht. printf to the rescue
code:
1
2
3
4
5
6
7
8
9
print_float () {
   let decval=$2
   let l=${#decval}-$1
   if ((l > 0 )); then
      echo ${decval:0:$l},${decval:$l:$1}
   else
      printf "0,%0*u\n" $1 $decval
   fi
}


PS: variable l was misschien niet zo'n gelukkige keuze met het code-lettertype :)
PPS: Als je print_float geen newline wilt laten outputten dan moet je bij het echo command de -n optie meegeven en bij printf de \n uit de formatstring halen.
Wat ook nog een hardnekkig probleempje is;
code:
1
...

Als het script uit de routine komt (en er is geen daglicht), krijg ik bijna altijd
./getdata.sh: line 87: 4140 Terminated dd if=$PORT of=$OUT bs=1 count=31 2> /dev/null
Ik heb >/dev/null overal al gehad, maar ik krijg deze niet onderdrukt. Al komt het ook soms voor dat het helemaal niet optreedt.
In het voorbeeld wat SA007 gaf, krijg ik die melding helemaal niet.
Volgens mij heb ik er geen last van zodra het script als cron job gaat draaien, maar netjes vind ik het niet.
ook met
code:
1
2
if [ -n "`pidof dd`" ]; then
 killall dd 2>/dev/null

krijg ik de melding.
Die melding komt van bash zelf die meld dat een background process het loodje heeft gelegd. Dit gebeurd niet als je het background process mbv SIGINT beeindigt wordt maar 'dd' lijkt daar niet naar te luisteren. Gelukkig wacht bash met melden op een geschikt moment (vlak voor een wait of sleep, etc) om eventuele output niet te verstoren. Dit kan je gebruiken voor een workarround die het bericht naar /dev/null stuurt.

code:
1
2
3
4
5
6
silentbob () {
    sleep 1
}

kill $PID
silentbob 2>/dev/null


Kost je maar een seconde :)

PPPS: Is het niet netter om eerst 'dd' te killen en daarna pas het 'cp $ZERO $OUT' comand uit te voeren?

[ Voor 3% gewijzigd door Buffy op 28-02-2007 01:13 ]

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Buffy schreef op woensdag 28 februari 2007 @ 00:53:
[...]

Oeps, getallen kleiner dan nul, niet aan gedacht. printf to the rescue
code:
1
2
3
4
5
6
7
8
9
print_float () {
   let decval=$2
   let l=${#decval}-$1
   if ((l > 0 )); then
      echo ${decval:0:$l},${decval:$l:$1}
   else
      printf "0,%0*u\n" $1 $decval
   fi
}


PS: variable l was misschien niet zo'n gelukkige keuze met het code-lettertype :)
PPS: Als je print_float geen newline wilt laten outputten dan moet je bij het echo command de -n optie meegeven en bij printf de \n uit de formatstring halen.


[...]


Die melding komt van bash zelf die meld dat een background process het loodje heeft gelegd. Dit gebeurd niet als je het background process mbv SIGINT beeindigt wordt maar 'dd' lijkt daar niet naar te luisteren. Gelukkig wacht bash met melden op een geschikt moment (vlak voor een wait of sleep, etc) om eventuele output niet te verstoren. Dit kan je gebruiken voor een workarround die het bericht naar /dev/null stuurt.

code:
1
2
3
4
5
6
silentbob () {
    sleep 1
}

kill $PID
silentbob 2>/dev/null


Kost je maar een seconde :)

PPPS: Is het niet netter om eerst 'dd' te killen en daarna pas het 'cp $ZERO $OUT' comand uit te voeren?
_/-\o_
Goeie uitleg, ik had al het gevoel dat het sleep commando er op een of andere manier mee van doen had; toen ik daar wat mee rotzooide veranderde het regelnummer in de foutmelding.
Het killen gebeurde eerst ook al eerder in de routine, maar ik dacht dat het aan de plaats van het commando lag, dat ie die melding gaf. Maar dat is inderdaad dus niet zo.
Dat cp commando gaat er overigens zowieso uit, dat was tijdelijk om wat te stoeien met RRDTool. Ik ben inmiddels begonnen met een probeerseltje om de RRD te vullen, en ik denk niet dat ik daarvoor nullen moet invullen. Binnen RRDtool is namelijk al rekening gehouden met het feit dat data mogelijk niet altijd beschikbaar is.

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • SA007
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:15

SA007

Moderator Tweaking
De reden dat hij daar sleep doet is omdat dan je bash programma even onderbroken wordt (voor een seconde), en in die seconde print hij dan de Terminated melding.
Maar aangezien hij dan in een gedeelte zit waar de ouput van weggegooid wordt krijg je geen melding.

Je kan als het zin heeft die sleep nog kleiner maken, 0.01 oid, hij hoeft alleen even onderbroken te worden.

  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
SA007 schreef op donderdag 01 maart 2007 @ 14:01:
De reden dat hij daar sleep doet is omdat dan je bash programma even onderbroken wordt (voor een seconde), en in die seconde print hij dan de Terminated melding.
Maar aangezien hij dan in een gedeelte zit waar de ouput van weggegooid wordt krijg je geen melding.

Je kan als het zin heeft die sleep nog kleiner maken, 0.01 oid, hij hoeft alleen even onderbroken te worden.
Dat begreep ik al wel. Maar die sleep is wel cruciaal, want ik had al geprobeerd om de aanroep van de routine te devnullen. Maar dan komt ie dus alsnog later, bij de eerste sleep.
Maar ik ga het vanavond ff proberen.
Wbt getallen van 0.01
Bash kent alleen hele getallen volgens mij, dus ook sleep is minimaal 1 sec, toch?

Edit:
Het werkt inderdaad.
Om het script niet te lang te laten lopen, doe ik de aanroep van de routine gewoon meteen met 2>/dev/null. Dan vang ik 4 van de 5 meldingen al af als het donker is, en de laatste kan ik dan ergens anders evt wel afvangen, dat scheelt toch weer 4 seconden. Er zit in de routine immers zowieso al een sleep.

[ Voor 16% gewijzigd door Mistraller op 01-03-2007 23:45 ]

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Nou, de RRDtool grafiekjes doen het keurig, dat is goed gelukt. Er komt nog meer data in grafiekvorm denk ik, maar dit was ff het belangrijkste. Voor een voorbeeldje:

Afbeeldingslocatie: http://mystery.xs4all.nl/Pictures/soladin/solar_power_last_day.bak.png

Ik ben nu nog een paar laatste dingetjes aan het prutsen, maar volgens mij denk ik weer helemaal verkeerd.

In de ontvangen data zit in de array op positie 6 en 7 de errorcode, indien er iets gemeld wordt op de omvormer. (bv max output in hoogzomer :9 )
In hexwaarden:
00 00 geen error
01 00 Usol>
02 00 Usol<
04 00 no grid
08 00 Uac>
10 00 Uac<
20 00 Fac>
40 00 Fac<
80 00 temp
00 01 hardware failure
00 02 starting
00 04 Pmax
00 08 Imax

Dwz, elke bit vertegenwoordigt een errorcode. Er kunnen uiteraard bepaalde errors tegelijk getoond worden. Dit is natuurlijk een hele andere omzetting. De data zit echter als octal in de array, dus ik heb alweer zitten denken aan een soortement van lus waarin (indien de errorwaarden dus niet 0 zijn) steeds de waarde wordt afgetrokken tot ik uiteindelijk precies op nul uitkom.
Dan moet ik dus 16 keer een test doen om te weten wat de error precies is. En volgens mij is dat niet handig.

Ander probleem waar ik mee worstel is het wegschrijven van dagopbrengsten. Aangezien de totaalopbrengst al beschikbaar is, wil ik daarmee een eenvoudige csv file beschrijven.

Uiteraard mag dat maar 1 keer per dag, dus ik bedacht me dat ik dan per meting kijk of de laatste regel nog de datum van vandaag bevat, en zo ja, dan breek ik af.
Indien er dus een nieuwe dag aangebroken is, haal ik de laatste Wtot waarde op (die staat ergens in een tmp bestandje) trek die af van de nieuwe waarde, en de uitkomst gaat weer in de csv met nieuwe datum. Maar hoe ik daar nu een snel werkende routine van maak, ik zit alweer met echo te rommelen om data weer terug in variablen te krijgen... 8)7

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • SA007
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:15

SA007

Moderator Tweaking
Elke dag -> cron :)

Over het splitsen van die waardes, dat gaat het makkelijkste met een bitwise and, voorbeeldje met 4 error bits:

Bash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

ERROR=5

if let "$ERROR & 1"
then
  echo Fout 1 is opgetreden
fi
if let "$ERROR & 2"
then
  echo Fout 2 is opgetreden
fi
if let "$ERROR & 4"
then
  echo Fout 3 is opgetreden
fi
if let "$ERROR & 8"
then
  echo Fout 4 is opgetreden
fi

  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

MisTraller schreef op dinsdag 20 maart 2007 @ 00:27:
[...]

Ik ben nu nog een paar laatste dingetjes aan het prutsen, maar volgens mij denk ik weer helemaal verkeerd.

In de ontvangen data zit in de array op positie 6 en 7 de errorcode, indien er iets gemeld wordt op de omvormer. (bv max output in hoogzomer :9 )
In hexwaarden:
00 00 geen error
01 00 Usol>
02 00 Usol<
04 00 no grid
08 00 Uac>
10 00 Uac<
20 00 Fac>
40 00 Fac<
80 00 temp
00 01 hardware failure
00 02 starting
00 04 Pmax
00 08 Imax

Dwz, elke bit vertegenwoordigt een errorcode. Er kunnen uiteraard bepaalde errors tegelijk getoond worden. Dit is natuurlijk een hele andere omzetting. De data zit echter als octal in de array, dus ik heb alweer zitten denken aan een soortement van lus waarin (indien de errorwaarden dus niet 0 zijn) steeds de waarde wordt afgetrokken tot ik uiteindelijk precies op nul uitkom.
Dan moet ik dus 16 keer een test doen om te weten wat de error precies is. En volgens mij is dat niet handig.
Bit operators zijn inderdaad het beter om de error bitjes te checken.

Aangezien er meerdere error codes tegelijk kunnen voorkomen kun je dit niet mbv case-statement of sparse array oplossen. Wel zou je zeldzame error's tegelijk kunnen uitsluiten zodat je die niet telkens afzonderlijk hoeft te testen bv:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let errbits=${data[7]}*256+${data[6]}

errorstr=""

if (( errorbits & 0x384 )); then
    if (( errorbits & 0x04 )); then
        errorstr="nogrid ${errorstr}"
    fi
    if (( data[6] & 0x80 )); then
        errorstr="temp ${errorstr}"
    fi
    if (( data[6] & 0x100 )); then
        errorstr="hardware ${errorstr}"
    fi
    if (( data[6] & 0x200 )); then
        errorstr="starting ${errorstr}"
    fi
fi


De vraag is of dit echt merkbare snelheidswinst oplevert.
Ander probleem waar ik mee worstel is het wegschrijven van dagopbrengsten. Aangezien de totaalopbrengst al beschikbaar is, wil ik daarmee een eenvoudige csv file beschrijven.

Uiteraard mag dat maar 1 keer per dag, dus ik bedacht me dat ik dan per meting kijk of de laatste regel nog de datum van vandaag bevat, en zo ja, dan breek ik af.
Indien er dus een nieuwe dag aangebroken is, haal ik de laatste Wtot waarde op (die staat ergens in een tmp bestandje) trek die af van de nieuwe waarde, en de uitkomst gaat weer in de csv met nieuwe datum. Maar hoe ik daar nu een snel werkende routine van maak, ik zit alweer met echo te rommelen om data weer terug in variablen te krijgen... 8)7
Je wilt dus aan de hand van de laatste Wtot van de vorige dag de huidige dag opbrengst bepalen.
Het probleem is echter dat je pas de volgende dag weet wat de laatste (gemeten) Wtot van de vorige dag is (tenzij je een "null" meting als zonsonder beschouwt).

Wat je kan doen is in een tmp bestand elke gemeten Wtot waarde met een time-stamp weg te schrijven

code:
1
2
3
4
5
lineWtot=(`date -R`)
lineWtot[6]=   # get Wtot info

# schrijf nieuwe meting naar het tmp Wtot bestand
echo ${lineWtot[@]} >> ${tmpWtotfile}


Echter voor je de nieuwe waarde weg schrijft moet je de laatste regel inlezen om te checken of die tot de zelfde dag behoort. Indien niet dan is het (waarschijnlijk) de laatste Wtot waarde van de voorgaande dag. Dan kan je de uiteindelijke de dagopbrengst van de voorgaande dag opslaan en het ijkpunt voor de huidige dag vast leggen.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
lastWtot=(`tail -n 1 ${tmpWtotfile}`)

if (( lastWtot[1] != lineWtot[1] || lastWtot[2] != lineWtot[2] || lastWtot[3] != lineWtot[3] )); then
    # bereken dag opbrengst voorgaande dag
    firstWtot=(`head -n 1 ${tmpWtotfile}`)
    ${firstWtot[4]}="12:00:00"
    let ${firstWtot[6]}=${lastWtot[6]}-${firstWtot[6]}

    # schrijf dagopbrengst vorige dag weg naar dagopbrengst cvs bestand
    echo "${firstWtot[@]:0:5};${firstWtot[6]}" >> ${Wdayfile}

    # schrijf laatste Wtot meting van voorgaande dag naar tmpWtotfile als eerste regel
    echo "${lastWtot[@]}" > ${tmpWtotfile}
fi


De eerste regel van het tmpWtotfile bevat dus de laatste Wtot van de voorgaande dag welke je kan gebruiken om de dag opbrengst te berekenen.

Verder zul je wel error checking moeten doen voor het geval je script een tijdje stil heeft gelegen c.q. voor het eerst opstart :).

Probleem is echter dat datum strings lastig te vergelijken zijn. Je zou in het tmpWtotfile ook een dagnummer (extra) kunnen wegschrijven b.v.:

code:
1
2
3
4
 # epoch 1 jan 2001 (ignore 100 and 400 leapyear rules)
 d=(`date "+%Y %-j"`)
 (( dy=d[0]-2001 ))
 (( daynr = dy*365 + dy/4 + d[1] ))


Dan kan je makkelijker controleren of het een of meerdere dagen geleden is dat er een Wtot is weggeschreven.

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • Mistraller
  • Registratie: Oktober 2002
  • Laatst online: 01-02 22:33
Goed idee :)

PS leuk dat je klokje weer gelijk loopt ;)
Buffy schreef op dinsdag 27 maart 2007 @ 21:36:
[...]

...ook heel veel nuttige zaken...
Ook bruikbare tips, maar ik ga het toch iets anders doen om het niet al te moeilijk te maken. Ik heb nu voor een combinatie van beiden gekozen:

Voor wat betreft het schrijven van de totalen:

Iedere uitlezing doe ik het volgende:
code:
1
2
echo $Wtot > $WORKDIR/WtotAct
echo $Htot > $WORKDIR/HtotAct

Zodoende is er altijd een laatste waarde, zolang de omvormer heeft gedraaid.
Dit maak ik tevens op de statistieken pagina inzichtelijk middels:
code:
1
2
3
4
(( Wtoday = Wtot - `tail $WORKDIR/WtotLog` ))
(( Htoday = Htot - `tail $WORKDIR/HtotLog` ))
echo "<TR><TD>"`print_float 2 $Wtoday`" kWh</TD><TD>Opgeleverd vermogen vandaag</TD></TR>" >> $HTML
echo "<TR><TD>"`print_time 1 $Htoday`"</TD><TD>Draaitijd vandaag</TD></TR>" >> $HTML


Een ander stukje code verwerkt vervolgens de gegevens.
Omdat ik voorlopig alles binnen 1 script wil hebben, heb ik het even anders opgelost, maar het is natuurlijk hetzelfde idee als met Cron.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
MTIME=`date +%M`
HTIME=`date +%H`

if [ $HTIME = 23 ] && [ $MTIME = 55 ]; then
 fill_csv
fi

#CSV filler routine
fill_csv(){
let Wtoday=`tail WtotAct`-`tail WtotLog`
let Htoday=`tail HtotAct`-`tail HtotLog`
if (( Htoday = 0 )) ; then
  echo `date -R`":   Soladin heeft niet gedraaid vandaag" >> $LOG
  else
  tail WtotAct > WtotLog
  tail HtotAct > HtotLog
fi
echo `date +%d-%m-%y`";"`print_float 2 $Wtoday`";"`print_time 2 $Htoday` >> $CSV
}

Voordeel hiervan is dat er gewoon elke dag een waarde wordt weggeschreven naar de file, mocht er de hele dag geen uitlezing gedaan zijn, dan komen er gewoon nullen in de file. En pas wanneer een nieuwe uitlezing is gedaan, wordt de log geupdate met nieuwe actuele waarden. Doordat de routine altijd pas draait wanneer de zon zeker weg is, is het altijd de laatste waarde. (Het draaide eerst in de nacht, maar dan klopt de datum niet 8)7 )

De errorafhandeling:
code:
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
(( errbits = data[7] * 256 + data[6] ))
ErrorStr=""
if (( errbits != 0 )); then
    if (( errbits & 0x01 )); then
      ErrorStr="Usolar high. ${ErrorStr}"
    fi
    if (( errbits & 0x02 )); then
      ErrorStr="Usolar low. ${ErrorStr}"
    fi
    if (( errbits & 0x04 )); then
     ErrorStr="No grid. ${ErrorStr}"
    fi
    if (( errbits & 0x08 )); then
     ErrorStr="Uac high. ${ErrorStr}"
    fi
    if (( errbits & 0x10 )); then
      ErrorStr="Uac low. ${ErrorStr}"
    fi
    if (( errbits & 0x20 )); then
      ErrorStr="FreqAC high. ${ErrorStr}"
    fi
    if (( errbits & 0x40 )); then
      ErrorStr="FreqAC low. ${ErrorStr}"
    fi
    if (( errbits & 0x80 )); then
      ErrorStr="Temperature. ${ErrorStr}"
    fi
    if (( errbits & 0x100 )); then
      ErrorStr="Hardware. ${ErrorStr}"
    fi
    if (( errbits & 0x200 )); then
      ErrorStr="Starting. ${ErrorStr}"
    fi
    if (( errbits & 0x400 )); then
      ErrorStr="Pmax. ${ErrorStr}"
    fi
    if (( errbits & 0x800 )); then
      ErrorStr="Imax ${ErrorStr}"
    fi
    echo `date -R`":   Error message: $ErrorStr" >> $LOG
fi


Ik doorloop ze gewoon allemaal. Dit werkt voldoende snel naar mijn idee. Ik heb een tijdje gelogd, en er komt maar heel sporadisch een foutcode.

Ik heb verder de volgende routine nog gebouwd voor een fatsoenlijke tijdweergave:
code:
1
2
3
4
5
6
7
8
9
#create time output
print_time () {
   (( H = $2 /60 ))
   (( M = $2 - 60*H ))
case "$1" in
  "1" ) echo $H" Uur, "$M" Minuten";;
  "2" ) echo $H":"$M;;
esac
}

Deze kan op meerdere manieren output aanleveren. Leek me wel zinvol om dat in een routine op te nemen.

Ik ben nu in elk geval bijna zover dat het voor mijn gevoel compleet is.
Wat ik me nog afvraag, stel dat ik wel met meerdere scripts wil gaan werken om ze met cron te starten, is het dan met bash mogelijk om een .conf bestand te gebruiken voor de variabelen?

My solar panels | Soladin loggen? | Strava
---------------
Gemak dient de mens, moeite dient de mensheid.


  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

MisTraller schreef op donderdag 12 april 2007 @ 02:07:
[...]

Ik ben nu in elk geval bijna zover dat het voor mijn gevoel compleet is.
Wat ik me nog afvraag, stel dat ik wel met meerdere scripts wil gaan werken om ze met cron te starten, is het dan met bash mogelijk om een .conf bestand te gebruiken voor de variabelen?
Je kan mbv "source bestand" of gewoon ". bestand" de inhoud van een bestand include EN uit laten voeren. In het bestand kan je dan bash variable assignments (config bestand) en/of functie definities (library bestand) zetten.

Als je alles echter in een bestand wilt hebben dan kan je het script via een simlink onder een andere naam aanroepen en dan in het script aan de hand van $0 checken hoe het script werd aangeroepen en welke acties dus moeten worden uitgevoerd. ($0 bevat het letterlijke aanroeppad dus gebruik basename om de scriptnaam aftesplitsen).

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)

Pagina: 1