Acties:
  • +1 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
- UPDATE - Oplossing is vervangen door Domoticz waarmee ik slimme meter uitlees (USB-Serial P1 kabel
Nieuwste werkende code is volgens mij uit deze post.
---------------------------------------------------------------------------------------------------------------------------------------------------
Ik krijg binnenkort een slimme meter, en wil de P1 poort gaan uitlezen met een Arduino. Nadat de interessante waardes uit het telegram zijn gehaald wil ik die wegschrijven in een MySQL database op m'n NAS.

Het uitlezen van de meter is niet zo'n punt, dat werkt met deze sketch uitstekend. Het verwerken van de data naar een MySQL lukt mij echter niet. Het levert of een niet werkende sketch op (blijft telkens hangen op bepaalde regels), of incomplete data in de tabel. Ik weet niet goed waar te beginnen. Dat script looped elke regel opnieuw, dus ergens een GET request plaatsen gaat dan niet lekker.

Gewenste situatie:
Als er een telegram op de Arduino binnenkomt vanaf de slimme meter (elke 10sec spuugt de meter de waarden voor meterstanden + huidig verbruik eruithalen (wat bovenstaande sketch dus al doet) en die wegschrijven in de bijbehorende velden in de MySQL database. Geen moeilijke berekeningen met de data, of data opslaan, webpagina met grafieken.

Gewoon telegram ontvangen, benodigde data extracten, doorsturen naar MySQL en daarna wachten op het volgende telegram. De data staat in MySQL, en kan vervolgens met PHP + Highcharts mooi getoond worden (dit gedeelte heb ik voor een Arduino temperatuurlogger al werkend). Het toevoegen van data aan MySQL dmv een GET request is ook al werkend, dmv deze PHP pagina.
als ik dat script handmatig aanroep met p1.php?a=1000&b=2000&c=3000 dan krijg ik die waardes netjes in m'n MySQL database.

Ik open dit topic omdat er genoeg alternatieven zijn zoals:
Slimme/digitale meter uitlezen met een Raspberry Pi
Slimme meter via P1-poort loggen met een Netduino Plus
maar in mijn ogen is dat gewoon dikke overkill. Een Arduino Duemilanove (kloon van de Uno) + W5100 Ethernetshield kost op eBay geen drol (in totaal misschien ~18 euro ?).

Naar mijn idee wordt er veel te snel naar een Raspberry Pi gegrepen terwijl dit, zoals gezegd, naar mijn mening redelijk overkill is. Ik kan op internet alleen sketches vinden die of de data uit het telegram gewoon echoen in de Arduino Serial Monitor, of die gelijk weer erg ingewikkeld zijn (Solarmeter sketch, P1 to COSM) en dan de data ook nog eens naar een externe partij uploaden (PVOutput, COSM).

Wie kan mij helpen om een werkende Arduino sketch hiervoor te creëren? Ik kan me voorstellen dat er nog wel meer Tweakers hier belang bij hebben. In veel huizen zal al een NAS draaien, dus dan is alleen het uitlezen nog nodig, wat met de Arduino dus goedkoop kan.

Ik heb op dit moment nog geen slimme meter (komt volgende week), maar heb wel een andere Arduino (Nano) in gebruik als P1 dummy. Deze heb ik in gebruik met deze sketch: http://pastebin.com/rhfg0KWk welke ervoor zorgt dat er elke 10sec een telegram via een van de digitale pinnen wordt uitgespuugd (AltSoftSerial library). Mocht je zelf (nog) geen slimme meter hebben dan zou je dus kunnen testen op die manier...

TL;DR: Werkende Arduino sketch gezocht om slimme meter data in MySQL database te krijgen

[ Voor 5% gewijzigd door ThinkPad op 07-07-2015 09:53 . Reden: Linkje naar nieuwste code toegevoegd bovenaan ]


  • ProudElm
  • Registratie: Juni 2003
  • Laatst online: 08:07
php webpagina maken die je de waarde mee geeft als input en die dan de waarde wegschrijft in MySQL.
Dat doe ik althans hier.

Zal straks even mijn sketch opzoeken ;)

edit:
mm.. misschien volgende keer toch alles lezen..;) Je was dus al op die manier bezig, maar volgens mij is dat toch de enige manier? Vanuit Arduino via PHP naar MySQL?

Ik heb in ieder geval gebruik gemaakt van dit voorbeeld.
Je vervangt dan de url in het voorbeeld met je php pagina en waarde.

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String url = "/emoncms/input/post.json?node=0&csv=";
url += ConvertFloatToString(currentFlowStroom);

if (client.connect(myserver, 80)) {  //starts client connection, checks for connection
    Serial.println("connected");
    if (!isFake)
    {
        String send = "GET " + url;
        send += " HTTP/1.0";
        client.println(send); //download text
    }
    else
    {
        client.println("GET /arduino/index.php HTTP/1.0"); //download text
    }
    client.println(); //end of get request
}

[ Voor 71% gewijzigd door ProudElm op 14-08-2014 07:43 ]


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Klopt, zover was ik al. Aanroepen van PHP bestand met variabelen zorgt dat dat in m'n MySQL database komt.

Ik krijg het alleen niet voor elkaar om dat in die uitleessketch te integreren. Ik heb onderstaande al gemaakt, maar dat werkt niet goed, hij blijft dan in de serial monitor constant alleen het elektra verbruik laagtarief uitspugen.

Mijn hoop was dat iemand met net iets meer verstand van Arduino mij zou kunnen helpen :)
C++:
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
        #include <AltSoftSerial.h>
        #include <SPI.h>
        #include <Ethernet.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;

        byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
        IPAddress ip(192,168,4,7);
        IPAddress server(192,168,4,4);
        EthernetClient client;

        const int requestPin =  4;         
        char input; // incoming serial data (byte)
        bool readnextLine = false;
        #define BUFSIZE 75
        char buffer[BUFSIZE]; //Buffer for serial data to find \n .
        int bufpos = 0;
        long mEVLT = 0; //Meter reading Electrics - consumption low tariff
        long mEVHT = 0; //Meter reading Electrics - consumption high tariff
        long mETLT = 0; //Meter reading Electrics - generated electricity (Solar panels) low tariff
        long mETHT = 0; //Meter reading Electrics - generated electricity (Solar panels) high tariff
        long mEAV = 0;  //Meter reading Electrics - Actual consumption
        long mEAT = 0;  //Meter reading Electrics - Actual generated electricity (Solar panels)
        float mG = 0;   //Meter reading Gas
         
        void setup() {
          Serial.begin(9600);
          delay(1000);
          
          altSerial.begin(9600);
          delay(1000);

          Ethernet.begin(mac, ip);
          delay(1000);
          Serial.print("My IP address: ");
          Serial.println(Ethernet.localIP());
          
          //Set RTS pin high, so smart meter will start sending telegrams
          pinMode(requestPin, OUTPUT);
          digitalWrite(requestPin, HIGH);
        }
         
        void loop() {
        long tl = 0;
        long tld =0;
         
          if (altSerial.available()) {
            input = altSerial.read();
           
            // --- 7 bits setting ---
            input &= ~(1 << 7);
            char inChar = (char)input;
            // --- 7 bits setting ---
         
            //Serial.print(input); //Debug
         
            // Fill buffer up to and including a new line (\n)
            buffer[bufpos] = input&127;
            bufpos++;
         
            if (input == '\n') { // We received a new line (data up to \n)
         
              // 1-0:1.8.1 = Electricity consumption low tariff (DSMR v4.0)
              if (sscanf(buffer,"1-0:1.8.1(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mEVLT = tl * 1000 + tld;
                if (mEVLT > 0) {
                  Serial.print("Elektra - meterstand verbruik LAAG tarief (Wh): ");
                  Serial.println(mEVLT);
                  //mEVLT = 0;
                }
              }
         
              // 1-0:1.8.2 = Electricity consumption high tariff (DSMR v4.0)
              if (sscanf(buffer,"1-0:1.8.2(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mEVHT = tl * 1000 + tld;
                if (mEVHT > 0) {
                  Serial.print("Elektra - meterstand verbruik HOOG tarief (Wh): ");
                  Serial.println(mEVHT);
                  //mEVHT = 0;
                }
              }
         
              // 1-0:1.7.0 = Electricity consumption actual usage (DSMR v4.0)
              if (sscanf(buffer,"1-0:1.7.0(%ld.%ld%*s" , &tl , &tld) >0 ) {
                mEAV = tl * 1000 + tld * 10;
                if (mEAV > 0) {
                  Serial.print("Elektra - actueel verbruik (W): ");
                  Serial.println(mEAV);
                  //mEAV = 0;
                }
              }
         
              // 1-0:2.8.1 = Generated electricity low tariff (DSMR v4.0)
              if (sscanf(buffer,"1-0:2.8.1(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mETLT = tl * 1000 + tld;
                if (mETLT > 0) {
                  Serial.print("Elektra - meterstand teruglevering LAAG tarief (Wh): ");
                  Serial.println(mETLT);
                  //mETLT = 0;
                }
              }
         
              // 1-0:2.8.2 = Generated electricity high tariff (DSMR v4.0)
              if (sscanf(buffer,"1-0:2.8.2(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mETHT = tl * 1000 + tld;
                if (mETHT > 0) {
                  Serial.print("Elektra - meterstand teruglevering HOOG tarief (Wh): ");
                  Serial.println(mETHT);
                  //mETHT = 0;
                }
              }
         
              // 1-0:2.7.0 = Actual generated electricity (DSMR v4.0)
              if (sscanf(buffer,"1-0:2.7.0(%ld.%ld%*s" , &tl , &tld) >0  ) {
                mEAT = tl * 1000 + tld * 10;
                if (mEAT > 0) {
                  Serial.print("Elektra - actueel teruglevering (W): ");
                  Serial.println(mEAT);
                  //mEAT = 0;
                }
              }
         
              // 0-1:24.3.0 = Gas (DSMR v4.0)
              if (sscanf(buffer,"0-1:24.3.0(%6ld%4ld%*s" , &tl, &tld) > 0  ) {
                readnextLine = true; // we have to go to the next line
              }
              if (readnextLine){
                if (sscanf(buffer,"(%ld.%ld%*s" , &tl, &tld) >0  ) {
                  mG = float ( tl * 1000 + tld ) / 1000;
                  Serial.print("Gas - meterstand (m3): ");
                  Serial.println(mG);
                  Serial.println("");
                  readnextLine = false;
                }
              }
              
              httpRequest();
              // Empty buffer again (whole array)
              for (int i=0; i<75; i++)
              { buffer[i] = 0;}
              bufpos = 0;

              mEVLT = 0;
              mEVHT = 0;
              mEAV = 0;
              mETLT = 0;
              mETHT = 0;
              mEAT = 0;
              delay(1000);
              client.stop();

            }
          }
        }

void httpRequest() {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    client.print("GET /www/slimmemeter/p1.php?mEVLT=");
    client.print(mEVLT);
    client.print("&mEVHT=");
    client.print(mEVHT);
    client.print("&mEAV=");
    client.print(mEAV);
    client.print("&mG=");
    client.print(mG);
    client.println(" HTTP/1.1");
    client.println("Host: 192.168.4.4");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

    Serial.println("Connection OK!");

    Serial.print("GET /www/slimmemeter/p1.php?mEVLT=");
    Serial.print(mEVLT);
    Serial.print("&mEVHT=");
    Serial.print(mEVHT);
    Serial.print("&mEAV=");
    Serial.print(mEAV);
    Serial.print("&mG=");
    Serial.print(mG);
    Serial.println(" HTTP/1.1");
    Serial.println("Host: 192.168.4.4");
    Serial.println("User-Agent: arduino-ethernet");
    Serial.println("Connection: close");
    Serial.println();
  } 
  else {
    Serial.println("connection failed");
    client.stop();
  }
}

  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

ThinkPadd schreef op woensdag 13 augustus 2014 @ 20:45:
Het levert of een niet werkende sketch op (blijft telkens hangen op bepaalde regels), of incomplete data in de tabel. Ik weet niet goed waar te beginnen. Dat script looped elke regel opnieuw, dus ergens een GET request plaatsen gaat dan niet lekker.
Misschien extra relevante gegevens om hier te posten:
* Op welke regels hangt de sketch zich op? (printf debugging)
* Hoe zien de webserver logs er uit bij incomplete data? (kan namelijk alleen aan een incomplete url liggen zo te zien)
* Wat is het verschil in de sketch tussen een hangende Arduino of incomplete data?

Het klinkt allemaal als interrupt problemen.
Wat je kan proberen is tijdens de ethernet communicatie de P1 request pin laag maken en de seriële poort interrupts uitzetten.

Ik weet verder niet hoe de altSerial library werkt, maar je kan ook proberen eerst het hele telegram binnen te hengelen en daarna te parsen en te sturen.
Mogelijk dat de Serial.print() van regel 77 hierboven blocking is waardoor de rest van het telegram niet meer ontvangen wordt.

Losse opmerking die je kan negeren: een POST request is hier netter dan een GET omdat er side effects zijn.

[ Voor 12% gewijzigd door Proton_ op 14-08-2014 11:19 ]

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


  • ProudElm
  • Registratie: Juni 2003
  • Laatst online: 08:07
rare vraag.. Lees je de client ook uit? Ik deed dat eerst niet en kreeg daar door ook raar gedrag.. Ik heb dit toegevoegd:

C:
1
2
3
4
5
while (client.connected() && !client.available()) delay(1); //waits for data
    while (client.connected() || client.available()) { //connected or data available
        char c = client.read(); //gets byte from ethernet buffer
        //Serial.print(c); //prints byte to serial monitor 
    }

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Proton_ schreef op donderdag 14 augustus 2014 @ 11:05:
[...]

Misschien extra relevante gegevens om hier te posten:
* Op welke regels hangt de sketch zich op? (printf debugging)
* Hoe zien de webserver logs er uit bij incomplete data? (kan namelijk alleen aan een incomplete url liggen zo te zien)
* Wat is het verschil in de sketch tussen een hangende Arduino of incomplete data?

Het klinkt allemaal als interrupt problemen.
Wat je kan proberen is tijdens de ethernet communicatie de P1 request pin laag maken en de seriële poort interrupts uitzetten.

Ik weet verder niet hoe de altSerial library werkt, maar je kan ook proberen eerst het hele telegram binnen te hengelen en daarna te parsen en te sturen.
Mogelijk dat de Serial.print() van regel 77 hierboven blocking is waardoor de rest van het telegram niet meer ontvangen wordt.

Losse opmerking die je kan negeren: een POST request is hier netter dan een GET omdat er side effects zijn.
Thanks.

Moet wel zeggen dat m'n kennis van Arduino heel basaal is. De sketch die je ziet is grotendeels gecombineerd knip en plakwerk van andere sketches.

Zal eens kijken met dat printf debugging, al denk ik dat er gewoon nog iets mist in de sketch. Weet alleen niet wat. Heb namelijk die basis uitlees sketch gepakt, en toen deze: http://arduino.cc/en/Tutorial/WebClient tutorial gepakt om te kijken wat er nodig is om een GET request te doen.

Webserver logs weet ik zo niet of, en hoe ik die kan gebruiken. Webserver draait op een Synology, weet niet precies waar de logs staan. Zal dat nog even uitzoeken. Incomplete URL probeer ik uit te sluiten door in de Serial Monitor hetzelfde uit te spugen als wat de Arduino naar de webserver stuurt. Daarmee wil ik toonbaar maken wat de Arduino voor variabelen in de URL stopt (en of de URL compleet wordt opgebouwd).

Hangende Arduino / incomplete data zit niet echt verschil tussen. Probleem is gewoon dat hij niet netjes meer door het uitlezen heen loopt. Daarom wordt de database ook niet goed gevuld.

Die AltSoftSerial gebruik ik omdat de SoftwareSerial library van Arduino ruk is. Die kan niet goed om gaan met lange berichten op een hogere baudrate. Data komt dan verminkt binnen met allemaal garbage erin. Vandaar AltSoftSerial. Hardware Serial kan ook, maar dat is een beslissing voor later. Met alleen echoen naar serial monitor leest hij het perfect uit. Dat is dus geen issue.

Serial.print op regel 77 (het uitspugen) heeft weinig te maken met het AltSoftSerial (het binnenhalen).

POST is netter qua veiligheid doel je op zeker? Arduino gaat alleen in een intern netwerk gebruikt worden. GET is in deze situatie makkelijker te realiseren dan POST volgens mij.
ProudElm schreef op donderdag 14 augustus 2014 @ 11:48:
rare vraag.. Lees je de client ook uit? Ik deed dat eerst niet en kreeg daar door ook raar gedrag.. Ik heb dit toegevoegd:

C:
1
2
3
4
5
while (client.connected() && !client.available()) delay(1); //waits for data
    while (client.connected() || client.available()) { //connected or data available
        char c = client.read(); //gets byte from ethernet buffer
        //Serial.print(c); //prints byte to serial monitor 
    }
Dat is een goede, dat ben ik inderdaad vergeten, en zie dat ze dat in de WebClient tutorial wel doen. Zal daar straks eens mee aan de gang gaan.

  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

ThinkPadd schreef op donderdag 14 augustus 2014 @ 13:11:
POST is netter qua veiligheid doel je op zeker? Arduino gaat alleen in een intern netwerk gebruikt worden. GET is in deze situatie makkelijker te realiseren dan POST volgens mij.
Nee, het was de pedante ik. Daarom kan je het gevoeglijk negeren en gewoon iets werkends maken :)
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html sectie 9.1.2
[...[
Dat is een goede, dat ben ik inderdaad vergeten, en zie dat ze dat in de WebClient tutorial wel doen. Zal daar straks eens mee aan de gang gaan.
Waarschijnlijk is zoiets het probleem :)

Met printf debugging bedoel ik wat je al deed: dingen over de seriële poort gooien die je de interne staat vertellen.

Je programma werkt nu zo als ik het goed begrijp:
* Er komt een regel binnen over de software seriële poort
* De regel wordt geparsed
* De database wordt bijgewerkt over ethernet
* De volgende regel wordt geparsed

De software seriële poort werkt waarschijnlijk met interrupts. De ethernetshield ook.
De processor kan maar één ding tegelijk dus als de pin op de seriële poort verandert terwijl hij met ethernet bezig was kan de pin alweer veranderd zijn eer de interrupt handler wordt gerund -> data mist.

Vandaar het idee om pas de database aan te passen als het hele telegram binnen is.

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Proton_ schreef op donderdag 14 augustus 2014 @ 13:43:
[...]
Vandaar het idee om pas de database aan te passen als het hele telegram binnen is.
Dat is ook precies wat ik wil gaan doen. Aan het einde van een telegram de hele reut versturen. Maar dat lukt me tot nu toe dus nog niet.

Regel voor regel is not-done, dan moet je een stuk of 6 GET-requests uitvoeren. Ook krijg je alles dan niet netjes in één rij in de tabel.

Waar moet ik trouwens die client.read plaatsen? In het eerste stuk van de httpRequest() functie?
Dus waar ik nu:
C++:
1
2
3
void httpRequest() {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
heb staan? Ook omdat dat stukje met 'while' is, ipv 'if'. In de WebClient tutorial doen ze het in de loop, en dan met een 'if'. Maar dat gaat bij mij niet op omdat het buiten de loop in de httpRequest functie gebeurt..

[ Voor 32% gewijzigd door ThinkPad op 14-08-2014 13:59 ]


  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

Aha, dat is wel wat er nu gebeurt: zodra er een \n binnenkomt start de parsing (regel 71) en wordt op regel 147 direct de database bijgewerkt.

Je moet dus het einde van een telegram detecteren (hoe heb ik ook niet paraat, sorry :)) en alleen dan httpRequest() doen.

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

De code van ProudElm hoort na regel 181 (en voor regel 198)

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Het einde van een telegram detecteren kan door te zoeken naar een '!' (uitroepteken). Die wordt altijd aan het einde van een telegram verstuurd.

Ik zal er straks even mee aan de gang gaan, moet nu even weg.

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Ik heb nu onderstaande code. Problemen die ik nu heb:
  • In de serial monitor zie ik maar één keer de waarden uitgespuugd worden als de Arduino geboot is. Een 2e telegram wordt niet ge-echoed in de Serial Monitor, moet eerst de Arduino weer resetten.
    Start ik de Arduino echter met de netwerkkabel losgekoppeld dan worden wel de waarden uit elk telegram netjes in de serial monitor weergegeven + "connection failed" telkens wanneer er een telegram binnenkomt (op m'n P1 dummy laat ik LED branden als hij iets uitstuurt).
  • De "Serial.print" tekst vanaf regel 191 t/m 201 wordt helemaal niet weergegeven in de Serial Monitor... hoe kan dit?
  • In de database gebeurt nog 0,0 (tabel blijft leeg). Maar dit zal aan een van bovenstaande problemen liggen denk ik.
Tevens is het mij niet duidelijk hoe ik zoek naar het einde van het telegram. Moet dat door if (input == '!') of if (input == 0x21) (hex voor uitroepteken), of if (input == 33) (decimaal voor uitroepteken)
De variabele 'input' definieer ik in het begin als 'char'. Welke variant moet ik dan gebruiken? (ASCII, hex, dec). Of beter in plaats van 'if input' gebruiken, voor sscanf(buffer) kiezen? Ik weet echter niet goed hoe ik daarmee naar een uitroepteken moet zoeken.

C++:
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
        #include <AltSoftSerial.h>
        #include <SPI.h>
        #include <Ethernet.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;

        byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
        IPAddress ip(192,168,4,7);
        IPAddress server(192,168,4,4);
        EthernetClient client;

        const int requestPin =  4;         
        char input; // incoming serial data (byte)
        bool readnextLine = false;
        #define BUFSIZE 75
        char buffer[BUFSIZE]; //Buffer for serial data to find \n .
        int bufpos = 0;
        long mEVLT = 0; //Meter reading Electrics - consumption low tariff
        long mEVHT = 0; //Meter reading Electrics - consumption high tariff
        long mETLT = 0; //Meter reading Electrics - generated electricity (Solar panels) low tariff
        long mETHT = 0; //Meter reading Electrics - generated electricity (Solar panels) high tariff
        long mEAV = 0;  //Meter reading Electrics - Actual consumption
        long mEAT = 0;  //Meter reading Electrics - Actual generated electricity (Solar panels)
        float mG = 0;   //Meter reading Gas
         
        void setup() {
          Serial.begin(9600);
          delay(1000);
          
          altSerial.begin(9600);
          delay(1000);

          Ethernet.begin(mac, ip);
          delay(1000);
          Serial.print("My IP address: ");
          Serial.println(Ethernet.localIP());
          
          //Set RTS pin high, so smart meter will start sending telegrams
          pinMode(requestPin, OUTPUT);
          digitalWrite(requestPin, HIGH);
        }
         
        void loop() {
        long tl = 0;
        long tld =0;
         
          if (altSerial.available()) {
            input = altSerial.read();
           
            // --- 7 bits setting ---
            input &= ~(1 << 7);
            char inChar = (char)input;
            // --- 7 bits setting ---
         
            //Serial.print(input); //Debug
         
            // Fill buffer up to and including a new line (\n)
            buffer[bufpos] = input&127;
            bufpos++;
         
            if (input == '\n') { // We received a new line (data up to \n)
         
              // 1-0:1.8.1 = Electricity consumption low tariff (DSMR v4.0)
              if (sscanf(buffer,"1-0:1.8.1(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mEVLT = tl * 1000 + tld;
                if (mEVLT > 0) {
                  Serial.print("Elektra - meterstand verbruik LAAG tarief (Wh): ");
                  Serial.println(mEVLT);
                  //mEVLT = 0;
                }
              }
         
              // 1-0:1.8.2 = Electricity consumption high tariff (DSMR v4.0)
              if (sscanf(buffer,"1-0:1.8.2(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mEVHT = tl * 1000 + tld;
                if (mEVHT > 0) {
                  Serial.print("Elektra - meterstand verbruik HOOG tarief (Wh): ");
                  Serial.println(mEVHT);
                  //mEVHT = 0;
                }
              }
         
              // 1-0:1.7.0 = Electricity consumption actual usage (DSMR v4.0)
              if (sscanf(buffer,"1-0:1.7.0(%ld.%ld%*s" , &tl , &tld) >0 ) {
                mEAV = tl * 1000 + tld * 10;
                if (mEAV > 0) {
                  Serial.print("Elektra - actueel verbruik (W): ");
                  Serial.println(mEAV);
                  //mEAV = 0;
                }
              }
         
              // 1-0:2.8.1 = Generated electricity low tariff (DSMR v4.0)
              if (sscanf(buffer,"1-0:2.8.1(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mETLT = tl * 1000 + tld;
                if (mETLT > 0) {
                  Serial.print("Elektra - meterstand teruglevering LAAG tarief (Wh): ");
                  Serial.println(mETLT);
                  //mETLT = 0;
                }
              }
         
              // 1-0:2.8.2 = Generated electricity high tariff (DSMR v4.0)
              if (sscanf(buffer,"1-0:2.8.2(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mETHT = tl * 1000 + tld;
                if (mETHT > 0) {
                  Serial.print("Elektra - meterstand teruglevering HOOG tarief (Wh): ");
                  Serial.println(mETHT);
                  //mETHT = 0;
                }
              }
         
              // 1-0:2.7.0 = Actual generated electricity (DSMR v4.0)
              if (sscanf(buffer,"1-0:2.7.0(%ld.%ld%*s" , &tl , &tld) >0  ) {
                mEAT = tl * 1000 + tld * 10;
                if (mEAT > 0) {
                  Serial.print("Elektra - actueel teruglevering (W): ");
                  Serial.println(mEAT);
                  //mEAT = 0;
                }
              }
         
              // 0-1:24.3.0 = Gas (DSMR v4.0)
              if (sscanf(buffer,"0-1:24.3.0(%6ld%4ld%*s" , &tl, &tld) > 0  ) {
                readnextLine = true; // we have to go to the next line
              }
              if (readnextLine){
                if (sscanf(buffer,"(%ld.%ld%*s" , &tl, &tld) >0  ) {
                  mG = float ( tl * 1000 + tld ) / 1000;
                  Serial.print("Gas - meterstand (m3): ");
                  Serial.println(mG);
                  Serial.println("");
                  readnextLine = false;
                }
              }
              
              
              // Empty buffer again (whole array)
              for (int i=0; i<75; i++)
              { buffer[i] = 0;}
              bufpos = 0;
          

            }
if (input == '!') {   uitroepteken geeft einde van telegram aan, dus we gaan data versturen
httpRequest();
 mEVLT = 0;
              mEVHT = 0;
              mEAV = 0;
              mETLT = 0;
              mETHT = 0;
              mEAT = 0;
              delay(1000);
              client.stop();
}        
          }
        }

void httpRequest() {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    client.print("GET /www/slimmemeter/p1.php?mEVLT=");
    client.print(mEVLT);
    client.print("&mEVHT=");
    client.print(mEVHT);
    client.print("&mEAV=");
    client.print(mEAV);
    client.print("&mG=");
    client.print(mG);
    client.println(" HTTP/1.1");
    client.println("Host: 192.168.4.4");
    client.println("User-Agent: arduino-ethernet");
    while (client.connected() && !client.available()) delay(1); //waits for data
    while (client.connected() || client.available()) { //connected or data available
        char c = client.read(); //gets byte from ethernet buffer
        //Serial.print(c); //prints byte to serial monitor 
    }
    client.println("Connection: close");
    client.println();

    Serial.println("Connection OK!");

    Serial.print("GET /www/slimmemeter/p1.php?mEVLT=");
    Serial.print(mEVLT);
    Serial.print("&mEVHT=");
    Serial.print(mEVHT);
    Serial.print("&mEAV=");
    Serial.print(mEAV);
    Serial.print("&mG=");
    Serial.print(mG);
    Serial.print("testbericht1234");
  } 
  else {
    Serial.println("connection failed");
    client.stop();
  }
}

Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Dinsdag wordt de slimme meter geïnstalleerd, dat maakt het testen ook wat makkelijker.

Acties:
  • 0 Henk 'm!

  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

Ik denk dat de arduino nu wacht tot de webserver wat terugstuurt voordat de request compleet is.
Dat gebeurt dus niet -> hang.
C++:
1
2
3
4
5
6
7
8
    client.println("User-Agent: arduino-ethernet");
    while (client.connected() && !client.available()) delay(1); //waits for data
    while (client.connected() || client.available()) { //connected or data available
        char c = client.read(); //gets byte from ethernet buffer
        //Serial.print(c); //prints byte to serial monitor 
    }
    client.println("Connection: close");
    client.println();

veranderen in
C++:
1
2
3
4
5
6
7
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();
    //Request complete; empty recieve buffer
    while (client.available()) { //data available
        char c = client.read(); //gets byte from ethernet buffer
    }

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Je bent geweldig! Het werkt nu, HELD! :D Bijgewerkte code staat hier: http://pastebin.com/N7jHBTDu . Zal hem later ook nog in dit topic plaatsen als ik het allemaal heb afgerond.
My IP address: 192.168.4.7
Server IP address: 192.168.4.4
*** BEGIN LOOP ***
Elektra - meterstand verbruik LAAG tarief (Wh): 13000
Elektra - meterstand verbruik HOOG tarief (Wh): 1000
Elektra - meterstand teruglevering LAAG tarief (Wh): 26000
Elektra - actueel verbruik (W): 540
Gas - meterstand (m3): 15.48

----------------------------Versturen naar database--------------------------
Connection OK!
GET /www/slimmemeter/p1.php?mEVLT=13000&mEVHT=1000&mEAV=540&mG=15.48
-----------------------------------------------------------------------------

*** EINDE LOOP - Wachten op volgende telegram vanuit slimme meter ***

Database wordt ook netjes gevuld.

Alleen de timing is niet heel accuraat, hieronder de tijdstippen van de ingevoegde rijen:
2014-08-17 21:50:40
2014-08-17 21:50:32
2014-08-17 21:50:21
2014-08-17 21:50:10
2014-08-17 21:49:42
2014-08-17 21:49:28
2014-08-17 21:49:07
2014-08-17 21:48:46
2014-08-17 21:48:28
2014-08-17 21:48:10

Zoals je ziet is het verschil dus niet elke seconden (wat je zou verwachten), maar wisselt het nogal.
Opzich is het niet erg zolang hij geen metingen mist, maar toch... En zelfs als hij een meting overslaat is het ook niet erg, dan mis ik alleen het actuele verbruik. Meterstand telt toch op, dus aan het einde van de dag is het laatste rij van die dag minus de eerste = dagverbruik... Maar als het simpel te verhelpen valt dat het accurater gevuld wordt???

En zitten er verder nog dingen in de code die wellicht geoptimaliseerd moeten/kunnen worden?

Let wel, dit is dus allemaal getest met een 2e Arduino die ik om de 10sec een P1 telegram laat uitspugen.
Ga nu even kijken of ik die Arduino wat random spul kan laten uitspugen.

[ Voor 84% gewijzigd door ThinkPad op 17-08-2014 22:03 ]


Acties:
  • 0 Henk 'm!

  • noo
  • Registratie: Januari 2012
  • Niet online

noo

ThinkPadd schreef op zondag 17 augustus 2014 @ 21:41:
Alleen de timing is niet heel accuraat, hieronder de tijdstippen van de ingevoegde rijen:
2014-08-17 21:50:40
2014-08-17 21:50:32
2014-08-17 21:50:21
2014-08-17 21:50:10
2014-08-17 21:49:42
2014-08-17 21:49:28
2014-08-17 21:49:07
2014-08-17 21:48:46
2014-08-17 21:48:28
2014-08-17 21:48:10

Zoals je ziet is het verschil dus niet elke seconden (wat je zou verwachten), maar wisselt het nogal.
Opzich is het niet erg zolang hij geen metingen mist, maar toch... En zelfs als hij een meting overslaat is het ook niet erg, dan mis ik alleen het actuele verbruik. Meterstand telt toch op, dus aan het einde van de dag is het laatste rij van die dag minus de eerste = dagverbruik... Maar als het simpel te verhelpen valt dat het accurater gevuld wordt???
Je simulator stuurt de telegrammen niet om de 10 seconden maar om de iets meer dan 10 seconden omdat de tijd om het telegram te maken en te sturen ook mee telt. Wat je kan doen is aan het begin van je loop millis() opvragen en dan waar je nu je delay() van 10 seconden doet nog een keer millis() opvragen en dan 10000 - het verschil tussen die twee waarden gaan wachten.

Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Oké maar als ik het goed begrijp is dat in de definitieve situatie dus niet aan de orde omdat hij dan daadwerkelijk aan de meter hangt ipv aan de dummy?

Acties:
  • 0 Henk 'm!

  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

Fijn dat het werkt!
Dat is natuurlijk het meest belangrijk.
Wat tips voor verbetering:

* Druk het gasgebruik uit in liters, dan blijft alles integer logica wat de Arduino leuker vindt.
* Als de buffer gematched is wordt nog steeds geprobeerd hem opnieuw te matchen, te voorkomen door elke volgende if in een 'else' branch te zetten of mooier nog, bij te houden welke regel je verwacht
* Deze regels doen hetzelfde:
code:
1
2
            input &= ~(1 << 7);
            input = input&127;

* inChar wordt niet gebruikt
* Er gebeurt nu 6x bijna hetzelfde:
C++:
1
2
3
4
5
6
7
8
               if (sscanf(buffer,"1-0:2.8.2(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mETHT = tl * 1000 + tld;
                if (mETHT > 0) {
                  Serial.print("Elektra - meterstand teruglevering HOOG tarief (Wh): ");
                  Serial.println(mETHT);
                  //mETHT = 0;
                }
              }

Je kunt kijken of je dit kunt refactoren naar een functie:

bool tryParseLine( char* buffer, char* template, int* result)

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Proton_ schreef op maandag 18 augustus 2014 @ 22:00:
Fijn dat het werkt!
Dat is natuurlijk het meest belangrijk.
Wat tips voor verbetering:

* Druk het gasgebruik uit in liters, dan blijft alles integer logica wat de Arduino leuker vindt.
Waarom zou ik dat moeten doen? Niet lullig bedoeld hoor! De slimme meter spuugt m3 uit... Dan moet ik getallen gaan omrekenen.... Dat maakt het toch juist lastiger? En wat bedoel je met integer logica? 'int' ipv 'float' gebruiken? Dan ga ik toch de waardes na de komma missen?
* Als de buffer gematched is wordt nog steeds geprobeerd hem opnieuw te matchen, te voorkomen door elke volgende if in een 'else' branch te zetten of mooier nog, bij te houden welke regel je verwacht
Zit wat in idd :) Bijhouden welke regel ik verwacht is mij iets te moeilijk, maar een else branch moet wel lukken denk ik.

Dan wordt het dus zoiets als dit:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
if (A) {
   
        } else {
                if (B) {
           
                        } else {
                                if (C) {
           
                                        } else {
           
                                                }          
                                }   
                }           


Dus dat alles eigenlijk onder de eerste IF hangt bedoel je toch? Is wel een tikje efficiënter idd. Aantal opties om mee te matchen wordt dan steeds minder.
* Deze regels doen hetzelfde:
code:
1
2
            input &= ~(1 << 7);
            input = input&127;
Dat stukje is mij te ingewikkeld. input &= ~(1 << 7);
buffer[bufpos] = input&127;
In het tweede stukje wordt 'input &=' toch weer gebruikt :?
Wat zou ik er mee moeten doen als het hetzelfde is? Kan een van de twee weg ofzo?
* inChar wordt niet gebruikt
Ik zie het inderdaad, die kan eruit ja :)
* Er gebeurt nu 6x bijna hetzelfde:
C++:
1
2
3
4
5
6
7
8
               if (sscanf(buffer,"1-0:2.8.2(%ld%.%ld%*s" , &tl, &tld) >0 ) {
                mETHT = tl * 1000 + tld;
                if (mETHT > 0) {
                  Serial.print("Elektra - meterstand teruglevering HOOG tarief (Wh): ");
                  Serial.println(mETHT);
                  //mETHT = 0;
                }
              }

Je kunt kijken of je dit kunt refactoren naar een functie:

bool tryParseLine( char* buffer, char* template, int* result)
Klopt, maar hoe zou je daar een algemene functie van moeten maken? Je hebt immers specifieke stukjes tekst waar op gezocht moet worden (die '1-0.2.8.2' etc).

Bedankt voor je tips, wordt echt gewaardeerd! Zonder dit forum was ik er echt niet uitgekomen _O_

Morgen komt de slimme meter, dus dan de echte test. Heb ook al een blogpost over het geheel klaarstaan, die komt morgenmiddag wel live denk ik ;)

[ Voor 4% gewijzigd door ThinkPad op 18-08-2014 22:39 ]


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Slimme meter hangt :) Er is een Kaifa MA105 + Itron G4 RF1 eV WL opgehangen.

Met een USB kabel gebaseerd op CH340 chipset kan ik de meter uitlezen op 115200 8N1 met m'n laptop.
De output van de meter die ik met m'n laptop heb opgevangen staat hier: http://pastebin.com/ZzFmLXvj

Met de Arduino lukte het aanvankelijk niet (baudrate op regel 40 aangepast naar 115200). Het bleek dat de data geïnverteerd binnenkwam. Met een transistor heb ik het signaal non-inverted gemaakt (plaatje van internet).

Ook heb ik om het te laten werken regel 61, input &= ~(1 << 7); eruit gehaald omdat mijn meter gewoon op 8N1 de data uitstuurt ipv 7N1. Kan ik dit zo laten of moet ik dat anders aanpakken?

Het actuele verbruik kan ik nu uitlezen. De telwerken voor elektra en gas nog niet, maar die zijn beiden nog 0 :+ Nog even geduld hebben dus.

Het viel mij echter op dat het actuele verbruik niet wordt weergegeven zoals het moet. De arduino spuugt 1950 uit, terwijl het verbruik op dat moment 0.195 kW was (kan ik in het display van de meter zien).

Toen ik de waterkoker aanzette was het actuele verbruik 2.087, maar de Arduino maakte hier 2850 van. Het verbruik schommelt natuurlijk (waardoor waarde in tabel iets achter kan lopen op display), maar volgens mij gaat er iets met een komma/omrekenen niet goed. Zou dit door mEAV = tl * 1000 + tld * 10; (regel 95) komen?

Ook upload de Arduino soms een 0 naar de tabel, terwijl ik vanalles aan heb staan.

Kortom, het werkt opzich, maar er moeten nog wat aanpassingen gedaan worden.

[ Voor 103% gewijzigd door ThinkPad op 19-08-2014 11:39 ]


Acties:
  • 0 Henk 'm!

  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

ThinkPadd schreef op maandag 18 augustus 2014 @ 22:31:
[...]
De slimme meter spuugt m3 uit... Dan moet ik getallen gaan omrekenen.... Dat maakt het toch juist lastiger? En wat bedoel je met integer logica? 'int' ipv 'float' gebruiken? Dan ga ik toch de waardes na de komma missen?
Je moet natuurlijk niets en voor een float is ook wat te zeggen :)
Wat gebeurt er nu: in de sscanf() worden 2 gehele decimale getallen verwacht met een punt ertussen (%d.%d). De integers tl en tld bevatten de resultaten en die worden gecombineerd tot 1 stand in Wh.
Behalve bij gas: daar wordt het gecombineerd en door 1000 gedeeld in een float.
Dit maakt het programma niet consequent. Als je voor liters kiest hoef je die deling niet te doen.
Dan wordt het dus zoiets als dit:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
if (A) {
   
        } else {
                if (B) {
           
                        } else {
                                if (C) {
           
                                        } else {
           
                                                }          
                                }   
                }           


Dus dat alles eigenlijk onder de eerste IF hangt bedoel je toch? Is wel een tikje efficiënter idd. Aantal opties om mee te matchen wordt dan steeds minder.
Dat kan inderdaad, het volgende is ook geldige syntax en is wat overzichtelijker:
C++:
1
2
3
4
5
6
7
8
9
if (A) {
   
} else if (B) {
           
} else if (C) {

} else {
           
}          
Dat stukje is mij te ingewikkeld. input &= ~(1 << 7);
buffer[bufpos] = input&127;
In het tweede stukje wordt 'input &=' toch weer gebruikt :?
Wat zou ik er mee moeten doen als het hetzelfde is? Kan een van de twee weg ofzo?
Het is inderdaad lastig om te zien, maar ~(1 << 7) is een ingewikkelde manier om 127 te schrijven: de eerste 7 bits op 1 en de laatste bit op 0.
Daar een bitwise and (&) mee, zorgt dat alle karakters tussen 0 en 127 vallen.
buffer[bufpos] = input; is voldoende want input &= ~(1 << 7); heeft al voor 7bits gezorgd.
Klopt, maar hoe zou je daar een algemene functie van moeten maken? Je hebt immers specifieke stukjes tekst waar op gezocht moet worden (die '1-0.2.8.2' etc).
De specifieke stukjes tekst worden dan een parameter van de nieuwe functie.
Als je dat voor elkaar krijgt ben je al een heel eind met C++ ;)
Ik heb de code nu wel tegen een standaard gehouden waar ik een collega ook aan zou houden; voor een hobbyist is dat wat overkill waarschijnlijk :)

Probeer je telegram van pastebin eens in je simulator. Werkt het dan ook niet?

[ Voor 5% gewijzigd door Proton_ op 19-08-2014 12:10 ]

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


Acties:
  • 0 Henk 'm!

  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

ThinkPadd schreef op dinsdag 19 augustus 2014 @ 10:28:Zou dit door mEAV = tl * 1000 + tld * 10; (regel 95) komen?
Yup het voorbeeld had denk ik minder cijfers achter de komma :)

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Thanks, ik zal er straks nog even weer naar kijken.

Blogpost staat ook live :) ThinkPad's TweakBlog: Slimme meter P1 poort uitlezen met Arduino en waarden opslaan in MySQL database



Edit: In de tussentijd even verder geknutseld. Heb die rare constructies met 'variabeleXYZ = tl * 1000 + tld *10' etc eruit gesloopt. Functie voor gasverbruik ook iets aangepast, idd naar liters zoals je zei. Output lijkt nu in orde:
*** BEGIN LOOP ***
Elektra - meterstand verbruik LAAG tarief (Wh): 5
Elektra - actueel verbruik (W): 150
Gas - meterstand (liters): 533.00

----------------------------Versturen naar database--------------------------
Connection OK!
GET /www/slimmemeter/p1.php?mEVLT=5&mEVHT=0&mEAV=150&mG=533.00
-----------------------------------------------------------------------------

*** EINDE LOOP - Wachten op volgende telegram vanuit slimme meter ***

Ik zit alleen nog met een vreemd issue dat het actuele verbruik soms naar 0 springt. Valt in de grafiek natuurlijk gelijk op ;)
In de tabel staat dan de waarde 0. Dit kan niet, want er staat vanalles aan. Maar hij laat "Actuele verbruik: XXX watt" dan ook niet in de seriele monitor zien. Beetje vreemd. De waarde voor gas is vaak nog wel gevuld (die verderop in de sketch na actueel verbruik wordt geraadpleegd) maar ook een aantal keren blijft die ook leeg.
Hieronder stukje van waar het fout gaat:
+----+---------------------+-------------+-------------+-----------------+--------+
| id | time | laag_tarief | hoog_tarief | huidig_verbruik | gas |
+----+---------------------+-------------+-------------+-----------------+--------+
| 13 | 2014-08-20 02:12:14 | 5 | 0 | 0 | 533.00 |
| 71 | 2014-08-20 02:22:57 | 5 | 0 | 0 | 533.00 |
| 41 | 2014-08-20 02:17:55 | 5 | 0 | 0 | 533.00 |
| 34 | 2014-08-20 02:16:44 | 5 | 0 | 0 | 533.00 |
| 47 | 2014-08-20 02:18:55 | 5 | 0 | 0 | 533.00 |
| 55 | 2014-08-20 02:20:16 | 5 | 0 | 0 | 0.00 |
| 60 | 2014-08-20 02:21:07 | 5 | 0 | 0 | 533.00 |
| 67 | 2014-08-20 02:22:17 | 5 | 0 | 10 | 533.00 |
| 83 | 2014-08-20 02:24:58 | 5 | 0 | 100 | 533.00 |

(Gesorteerd op kolom 'huidig_verbruik'). Kan er niet echt de vinger op leggen waar het fout gaat....
Ook zat er een keer een gigantisch hoge stand tussen:
laag_tarief: 892219440
hoog_tarief: 1831482163 (terwijl die normaal constant 0 is)
huidig_verbruik: 99 (lijkt wel te kloppen, gezien andere metingen)
gas: 533.00 (klopt ook).

Heel raar, lijkt wel alsof het uitlezen niet lekker gaat ofzo?

Die IF branches heb ik overigens ook geprobeerd, maar dat kreeg ik ook niet 123 klaar. In de laatste 'else' had ik een Serial.print 'connection failed' staan. Bij het runnen van de code op de Arduino gaf hij alleen die connection failed constant aan.

[ Voor 198% gewijzigd door ThinkPad op 20-08-2014 02:30 ]


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Iemand nog een oplossing voor dat het actuele verbruik soms naar 0 springt en dat de meterstanden voor elektra soms als enorm hoge waardes worden weggeschreven in de tabel?

Verder ga ik het script denk ik aanpassen zodat het eens per minuut wegschrijft ipv elke 10sec. Dat is nogal overkill ;) Ik zou alleen wel graag het actuele verbruik elke 10sec uit de Arduino willen halen zodat ik dit kan tonen op een pagina. De resolutie van 10sec is immers beschikbaar, dus het zou zonde zijn om die resolutie te vergroten naar 1 min.

Ik heb in gedachten om het actuele verbruik in de loop te laten zoals deze nu is, dat zodra er een telegram binnenkomt = wegschrijven naar database. Het extraheren + wegschrijven van meterstanden wil ik dan in een loop doen die ik dmv 'millis()' elke minuut laat lopen. Is dat een goede opzet of is er een slimmere/betere manier?

Ik toon het huidige verbruik nu op een pagina als tekst ("Huidig verbruik: 145W"). Code is gewoon <? php echo $huidig_verbruik?>. Misschien iets met JSON doen dat de Arduino op aanvraag het actuele verbruik uitspuugt? Dan hoef ik ook niet elke 10sec naar m'n MySQL database te schrijven....

[ Voor 14% gewijzigd door ThinkPad op 20-08-2014 23:52 ]


Acties:
  • 0 Henk 'm!

  • gekkie
  • Registratie: April 2000
  • Laatst online: 14:56
je zou ook 10 seconden kunnen loggen .. en elke dag s'nachts met een scriptje de handel kunnen aggregeren .. kun je op de dag zelf .. of in de week zelf .. nog alles in detail zien .. en daarna alleen op hoofdlijnen (in principe wat RRD automagisch voor je doet)

En de enorme hoge en lage waardes (heb ze zelf nog nooit gezien) .. misschien gewoon een simpel filtertje ? .. indien 0 of de capaciteit van een volledige energie central .. neem de vorige waarde ?

(of eerst de ruwe data eens loggen indien het parsen gekke waarden heeft opgeleverd .. wellicht is het een foutje in je parser)

[ Voor 12% gewijzigd door gekkie op 21-08-2014 00:00 ]


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Aggregeren is inderdaad ook nog een idee ja. Eens uitzoeken hoe anderen dit doen met een slimme meter.

En ik heb nu gewoon een aantal MySQL queries lopen die de onrealistische waarden uit de database verwijderen. Maar dat is niet de manier waarop ik wil werken. Waarschijnlijk gaat het uitlezen niet goed en komt er daardoor een verkeerde waarde in de database. Ik los het liever bij de bron op ;)

Er zit trouwens nog een bug in de code zie ik nu. Het verbruik is nog nooit boven de 1000W geweest :P Gaat iets niet goed met het parsen van het uitgelezen getal dus.

[ Voor 25% gewijzigd door ThinkPad op 21-08-2014 01:58 ]


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Omdat sommige getallen niet goed worden uitgelezen ben ik aan het kijken naar de 'sscanf()' parameter. Ik krijg het alleen niet voor elkaar om de waarden uit het telegram te extracten.

Ik heb bijv. deze regel: 1-0:1.8.1(000014.406*kWh) (meterstand elektra laagtarief)

En daar gooi ik
C++:
1
2
if (sscanf(buffer,"1-0:1.8.1(%6ld%.%3ld%*s" , &tl, &tld) >0 ) {
                mEVLT = tl + tld;
tegenaan.

Dan krijg ik alleen 14 terug. Ik zit daarom te proberen om ipv een long decimal (ld) de gehele waarde tussen de haakjes in een float te zetten (omdat de waarde in het telegram ook een float/decimal is gezien de decimale punt). Maar ik krijg het maar niet voor elkaar.

Op aanraden van een tip uit het Arduino topic: RobV in "[Discussie] Arduino-topic" probeer ik het nu zo:
C++:
1
2
3
4
float number = 0;
char sbuf[32];
          if (sscanf(buffer,"1-0:1.8.1(%6f*%s)" , &number, sbuf) == 2 ){
                mEVLT = number;

Maar het resultaat blijft telkens nul....

Ik heb dit al doorgespit en allerlei operators geprobeerd, maar het wil maar niet lukken. Is het misschien beter om een andere functie te gebruiken? Aangezien dit geen Arduino functie is, maar een native C functie.
Doel is om de waarde tussen de haakjes, minus '*kWh' of '*m3' in de DB te krijgen.

[ Voor 4% gewijzigd door ThinkPad op 22-08-2014 15:57 ]


Acties:
  • 0 Henk 'm!

  • Infant
  • Registratie: Januari 2008
  • Laatst online: 01-05 16:37

Infant

It's a floating Dino!

AVR Studio doet standaard in iedergeval niks met floats printen of scannen. Ik scanf ze niet, maar als ik floats wil printen moet ik een aparte library daarvoor linken.

http://forum.arduino.cc/index.php?topic=53894.0;wap2

Voor sscanf zou dat kennelijk ook moeten.

Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Code voor een float scanner. Let op dit is uit het hoofdje.

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
//e.g. input "001234.00434" -> 1234.434

float scanFloat(char *data)
{
   float intPart = 0;
   float fractionPart = 0;
   float fractionDigit = 1;

   while(*buf >= '0' && *buf <= '9')
   {
       intPart *= 10;
      intPart += (*buf++)-'0';
   }

   if(*buf == '.')
   {
     buf++;   //. overslaan

     while(*buf >= '0' && *buf <= '9')
     {
        fractionDigit /= 10;      //eerste stap 0.1, tweede stap 0.01, etc.
        int digit = (*buf++)-'0';

       fractionPart += digit * fractionDigit;
     } //while
   } //if

   //string eindigt met '\0' of een non-digit.
  return intPart + fractionPart;
}


Edit:

Als je nou de scanf gebruikt om de waarde uit de string te halen (dus door middel van %s in de een string buffer/sbuf), dan stop je die string (no ontdaan van alle haakjes en *kWH etc) in de parsefunctie.

[ Voor 13% gewijzigd door RobV op 22-08-2014 16:47 ]

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Bedankt, maar het is in de tussentijd al gelukt lijkt het.

Meterstand (000014.406*kWh) met
C++:
1
2
3
4
5
long mEVLT = 0;
    if (sscanf(buffer,"1-0:1.8.1(%ld.%ld" ,&tl, &tld)==2){
                tl *= 1000;
                tl += tld;
                mEVLT = tl;

Geeft 14406, dit deel ik met PHP weer door 1000 zodat ik op 14.406 kom in de database.

Huidig verbruik (02.184*kW) / (00.084*kW) met:
C++:
1
2
3
4
long mEAV = 0;
if (sscanf(buffer,"1-0:1.7.0(%ld.%ld" ,&tl , &tld) == 2)
              { 
                mEAV = (tl*1000)+tld;

Geeft 2184 (hoog verbruik), of 84 (bij een laag verbruik).

Alleen gas wil nog niet lukken. Input is 0-1:24.2.1(000103170000W)(00001.180*m3)
C++:
1
2
 if (sscanf(buffer,"0-1:24.2.1(%*s%*c)(%ld.%ld%*s)" , &tl, &tld) == 2 ) {
                mG = tl * 1000 + tld; 

Hij spuugt hem nu uit als 0 (nul). Ik vermoed dat hij struikelt over die eerste waarde + letter 'W' tussen de haakjes. Ik probeer dat te negeren met '%*s' en '%*c' maar dat werkt dus niet..

En ik zie dat ik nogsteeds die gare bug erin heb zitten dat hij soms de waarde 0 (nul) naar de database stuurt (meterstand of huidig verbruik staat er dan soms ineens als 0 in). Kan niet goed vinden waar dat vandaag komt.

[ Voor 18% gewijzigd door ThinkPad op 22-08-2014 17:49 ]


Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Tja het blijft rommelen zo.
Afbeeldingslocatie: http://i.imgur.com/FMrdIsk.png
De rode pijltjes geven aan dat je 5 parameters probeert te parsen. (waarom die *c en de *s)
De blauwe pijltjes zijn de adressen waar antwoord 1 en antwoord 2 moeten komen (waar zijn de andere 3), ten tenslotte test je of er 2 variabelen gevuld zijn (terwijl er 5 in je format staan) 8)7

Je komt er wel, maar wel scherp blijven hè!


EDIT: De %*s constructie kende ik niet..

[ Voor 6% gewijzigd door RobV op 22-08-2014 18:10 ]

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Het sterretje geeft aan dat daar een string/decimal/whatever zit, maar dat ik er niks mee wil doen. Moet ik er dan wel een variabele aanhangen (waar ik niks mee ga doen), en ook meenemen in de check? (==5)

En blijft idd rommelen, maarja ik ben nou eenmaal geen die-hard programmeur ;)

Het is dat slijtage van de Atmega328 meevalt... anders was hij al lang versleten denk ik, heb nou al zo vaak een paar tekentjes aangepast en dan hop, de hele sketch weer uploaden

Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
En dit?

(http://www.gammon.com.au/forum/?id=12153)
Trap #7: Trying to sscanf a float.


eg.


float foo;
char buf [] = "123.45";
sscanf (buf, "%f", &foo);


On the Arduino, sscanf does not support floats.

Suggest scanning into a %s field (a string) and then using atof on the result.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Thanks, dat is een goede inderdaad.

Maar is opzich niet nodig toch? Datatype is hetzelfde als bij elektra (ook ld, long double), en die pakt hij wel. Het is meer dat stukje ervoor wat hij ook probeert mee te nemen ofzo denk ik.

Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Ik denk dat de *s alles opslokt totaan het laatste haakje (sscanf is greedy). Het is geen regex parser die vooruit kan kijken.

[ Voor 24% gewijzigd door RobV op 22-08-2014 18:53 ]

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • noo
  • Registratie: Januari 2012
  • Niet online

noo

(Geen arduino bij de hand maar dit zou daar ook moeten werken)
Je kan je sscanf laten beginnen na het laatste open haakje zodat je format string simpel kan zijn:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <string.h>
#include <stdio.h>

int main(void)
{
    char *in = "0-1:24.2.1(000103170000W)(00001.180*m3)";
    int tl, tld;
    double l;

    if (sscanf(strrchr(in, '(') + 1, "%d.%d", &tl, &tld) == 2) {
        l = 1000 * tl + tld;
        printf("%1.f liter (tl = %d, tld = %d)\n", l, tl, tld);
    }

    return (0);
}

Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Dankje :) Zoiets had ik zelf ook al geprobeerd (zoeken naar 'W()<hier het interessante gedeelte>*m3' maar het punt is dat er nog een soortgelijke regel in de output zit. Hier het telegram wat m'n meter uitspuugt: http://pastebin.com/ZzFmLXvj

Regel 27 is de goede regel, maar op regel 17 zit een regel die er qua haakjes op lijkt..

Acties:
  • 0 Henk 'm!

  • noo
  • Registratie: Januari 2012
  • Niet online

noo

ThinkPadd schreef op zaterdag 23 augustus 2014 @ 11:07:
Dankje :) Zoiets had ik zelf ook al geprobeerd (zoeken naar 'W()<hier het interessante gedeelte>*m3' maar het punt is dat er nog een soortgelijke regel in de output zit. Hier het telegram wat m'n meter uitspuugt: http://pastebin.com/ZzFmLXvj

Regel 27 is de goede regel, maar op regel 17 zit een regel die er qua haakjes op lijkt..
Geen probleem, aannemende dat het eerste deel van de string een telegram identificatie is, kan je de juiste sscanf doen:
code:
1
2
3
4
if (strncmp(in, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0) {
        if (sscanf(strrchr(in, '(') + 1, "%d.%d", &tl, &tld) == 2) {
                       ...
                }

Acties:
  • 0 Henk 'm!

  • mrc4nl
  • Registratie: September 2010
  • Laatst online: 17:45

mrc4nl

Procrastinatie expert

heej dit is interessant, ik heb een 2011 arduino liggen waar ik niets mee doe en ook een slimme meter hangen waar ik niets mee "doe" :P

binnenkort maar eens kijken

ora et labora


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
noo schreef op zaterdag 23 augustus 2014 @ 11:13:
[...]

Geen probleem, aannemende dat het eerste deel van de string een telegram identificatie is, kan je de juiste sscanf doen:
code:
1
2
3
4
if (strncmp(in, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0) {
        if (sscanf(strrchr(in, '(') + 1, "%d.%d", &tl, &tld) == 2) {
                       ...
                }
Het is gelukt met die code :) Dacht eerst dat het niet klopte, omdat het getal in de output niet overeenkwam met de gasmeter. Maar toen bedacht ik me dat de gasmeterstand maar eens per uur wordt doorgegeven. Als ik de meter met m'n laptop uitlees zie ik dezelfde waarde 8) Muchos bedanktos!

Final sketch staat hier: http://pastebin.com/N7jHBTDu
mrc4nl schreef op zaterdag 23 augustus 2014 @ 11:17:
heej dit is interessant, ik heb een 2011 arduino liggen waar ik niets mee doe en ook een slimme meter hangen waar ik niets mee "doe" :P

binnenkort maar eens kijken
Zie blogpost in m'n signature om je op weg te helpen :)

[ Voor 113% gewijzigd door ThinkPad op 23-08-2014 12:08 ]


Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
@ThinkPad, ik gebruik BitBucket voor al mijn source-projecten. BitBucket heeft unlimited private projects. En als je je even inleest in git supersimpel ook met Arduino code. Aan het eind van elk functiepunt (of halverwege) even een 'git commit' in de commandline (of via een GUI) en hoppa versiebeheer.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Thanks, misschien eens naar kijken inderdaad :)

Ondertussen heb ik geprobeerd om de code aan te passen zodat hij met een interval van 1 minuut de data uitleest ipv constant (wat om de 10sec is omdat de meter met die frequentie data uitspuugt). Dit heb ik gedaan mbhv 'millis()'

Helaas is de sketch nu broken, na meerdere minuten gewacht te hebben gebeurt er niks. In de serial console verschijnt alleen IP + server IP.

Komt het omdat ik alles wat voorheen in de normale loop stond binnen millis heb gezet, terwijl het misschien genoeg is om alleen de 'httpRequest()' in de millis-loop te zetten? Dat heb ik ook geprobeerd, maar dat was hetzelfde verhaal.

Ik gebruik als millis tutorial deze: http://arduino.cc/en/Tutorial/BlinkWithoutDelay (ja ik ben op de hoogte van de millis-overflow-na-50 dagen bug ;) ) In plaats van die 3 if/else regeltjes met de LED prak ik dan mijn code erin. (of alleen 'httpRequest' en het stukje om de uitgelezen waarden weer op 0 te zetten).

Hieronder de code:
C++:
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
include <AltSoftSerial.h>
#include <SPI.h>
#include <Ethernet.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;

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192,168,4,7);
IPAddress server(192,168,4,4);
EthernetClient client;

const int requestPin =  4;         
char input; // incoming serial data (byte)
bool readnextLine = false;
#define BUFSIZE 75
char buffer[BUFSIZE]; //Buffer for serial data to find \n .
int bufpos = 0;
long mEVLT = 0; //Meter reading Electrics - consumption low tariff
long mEVHT = 0; //Meter reading Electrics - consumption high tariff
long mEAV = 0;  //Meter reading Electrics - Actual consumption
long mEAT = 0;  //Meter reading Electrics - Actual generated electricity (Solar panels)
long mG = 0;   //Meter reading Gas


unsigned long PreviousMillis = 0;// For when millis goes past app 49 days. 
unsigned long interval = 60000;  // Wait between dumps (1 min)
unsigned long intervalTime;      // Global var tracking Interval Time

void setup() {
    Serial.begin(9600);
    delay(1000);

    altSerial.begin(115200);
    delay(1000);

    Ethernet.begin(mac, ip);
    delay(1000);
    Serial.print("My IP address: ");
    Serial.println(Ethernet.localIP());
    Serial.print("Server IP address: ");
    Serial.println(server);

    //Set RTS pin high, so smart meter will start sending telegrams
    pinMode(requestPin, OUTPUT);
    digitalWrite(requestPin, HIGH);

    //Delay stuff
    intervalTime = millis();  // Set initial target trigger time (right NOW!)
}

void loop() {
    unsigned long CurrentMillis = millis();

  if ( CurrentMillis < PreviousMillis ) // millis reset to zero?
  {
    intervalTime = CurrentMillis+interval;
}

  if ( CurrentMillis > intervalTime )  // Did we reach the target time yet?
  {
    intervalTime = CurrentMillis + interval;

    long tl = 0;
    long tld =0;

    if (altSerial.available()) {
        input = altSerial.read();

// --- 7 bits setting ---
//input &= ~(1 << 7);
        char inChar = (char)input;
// --- 7 bits setting ---

//Serial.print(input); //Debug

// Fill buffer up to and including a new line (\n)
        buffer[bufpos] = input&127;
        bufpos++;

if (input == '\n') { // We received a new line (data up to \n)
    if (sscanf(buffer,"1-0:1.8.1(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEVLT = tl;
        if (mEVLT > 0) {
            Serial.println("*** BEGIN LOOP ***");
            Serial.print("Elektra - meterstand verbruik LAAG tarief: ");
            Serial.println(mEVLT);
//mEVLT = 0;
        }
    }

// 1-0:1.8.2 = Electricity consumption high tariff (DSMR v4.0)
    if (sscanf(buffer,"1-0:1.8.2(%ld.%ld" ,&tl, &tld)==2) 
    {
        tl *= 1000;
        tl += tld;
        mEVHT = tl;
        if (mEVHT > 0) {
            Serial.print("Elektra - meterstand verbruik HOOG tarief: ");
            Serial.println(mEVHT);
//mEVHT = 0;
        }
    }

// 1-0:1.7.0 = Electricity consumption actual usage (DSMR v4.0)
    if (sscanf(buffer,"1-0:1.7.0(%ld.%ld" ,&tl , &tld) == 2)
    { 
        mEAV = (tl*1000)+tld;
        if (mEAV > 0) {
            Serial.print("Elektra - actueel verbruik (W): ");
            Serial.println(mEAV);
//mEAV = 0;
        }
    }

// 0-1:24.2.1 = Gas (DSMR v4.0) on Kaifa MA105 meter
    if (strncmp(buffer, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0) {
        if (sscanf(strrchr(buffer, '(') + 1, "%d.%d", &tl, &tld) == 2) {
            mG = (tl*1000)+tld; 
            Serial.print("Gas - meterstand (liters): ");
            Serial.println(mG);
            Serial.println("");
        }
    }


// Empty buffer again (whole array)
    for (int i=0; i<75; i++)
        { buffer[i] = 0;}
    bufpos = 0;


}
if (input == '!') {   //uitroepteken geeft einde van telegram aan, dus we gaan data versturen
    httpRequest();
    mEVLT = 0;
    mEVHT = 0;
    mEAV = 0;
    mEAT = 0;
    //delay(1000);
    client.stop();
}        
}
}
else
{
    Ethernet.maintain();
}
}

void httpRequest() {
// if there's a successful connection:
    if (client.connect(server, 80)) {
        client.print("GET /www/slimmemeter/p1.php?mEVLT=");
        client.print(mEVLT);
        client.print("&mEVHT=");
        client.print(mEVHT);
        client.print("&mEAV=");
        client.print(mEAV);
        client.print("&mG=");
        client.print(mG);
        client.println(" HTTP/1.1");
        client.println("Host: 192.168.4.4");
        client.println("User-Agent: arduino-ethernet");
        client.println("Connection: close");
        client.println();
//Request complete; empty recieve buffer
while (client.available()) { //data available
char c = client.read(); //gets byte from ethernet buffer
}
client.println();
Serial.println("----------------------------Versturen naar database--------------------------");
Serial.println("Connection OK!");
Serial.print("GET /www/slimmemeter/p1.php?mEVLT=");
Serial.print(mEVLT);
Serial.print("&mEVHT=");
Serial.print(mEVHT);
Serial.print("&mEAV=");
Serial.print(mEAV);
Serial.print("&mG=");
Serial.println(mG);
Serial.println("-----------------------------------------------------------------------------");
Serial.println();
Serial.println("*** EINDE LOOP - Wachten op volgende telegram vanuit slimme meter ***");
} 
else {
    Serial.println("Connection failed");
    client.stop();
}
}

[ Voor 7% gewijzigd door ThinkPad op 26-08-2014 10:34 ]


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Iemand nog tips hoe ik de meter maar eens per minuut kan uitlezen en data versturen, ipv elke 10sec? Zoals gezegd lukt het met bovenstaande code niet.

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Dat komt (als ik de haakjes goed lees), omdat je timer loopt niet klopt en volgens mij reset je de 'previousMillis' nergens.

Advies: probeer eerst een lege sketch te maken in je Arduino die elke 6 second een led toggled. Doe dan je timing x10 en kopieer die lus dan naar deze sketch.

Advies #2: Je hebt nu alles in je loop() staan waardoor je geneste lus (loop) niet helder is. Prak de binnenkant van je lus in een aparte functie voor de helderheid. Zorg er altijd voor dat een lus op 1 beeldscherm past (ongeveer 15 regels). Je krijgt dan dit:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void loop()
{
   if(/* timer check statements */) 
   {
      doeJeDingHier();

      //update timer data.
   }
}

void doeJeDingHier()
{
   //blablabla;
}


Kijk ter vergelijking eens maar mijn code fragment (uit Aduro):

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void loop()
{
  while(Serial.available() > 0)
  {
     processIncomingBinary(Serial.read()); 
  }
    
  if(cloudAnimation.getCompleted())
  {
    cloudAnimation.reset(0,1);
  }
  
  if(noResponseEvent.hasElapsed(30*1000, false))
  {
      //set brightness to 0, effectively turning it off.
     brightnessAnimation.setToValue(0);
  }
  
  ...
}


Ik gebruik hier een eigen class om al mijn timing meuk in af te handelen `hasElapsed`.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

Nadat het interval verlopen is wordt er één karakter geparsed en dan weer 60 seconden gewacht.
Ik denk dat er daarna een buffer volloopt omdat de meter wel elke 10 seconden een telegram blijft sturen.
Dus:
Verzet de interval timer naar als een bericht is verwerkt. (regel 71 naar tussen regel 152 en 153)
Zet de enable pin laag als je geen bericht wil hebben (regel 152) en hoog als je er klaar voor bent (regel 71)
Tip: zet de hoop regels tussen de if(CurrentMillis > intervalTime){...} in een aparte functie.

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Merci mannen, vanavond maar even mee aan de slag :)
Eerst maar eens zorgen dat m'n MySQL database weer draait, vandaag nieuwe NAS binnengekomen.

Hebben jullie toevallig ook nog een ingeving waarmee ik het actuele verbruik nog wel steeds om de 10sec eruit kan krijgen? (Waarde uitspugen als ik http://arduino?huidigverbruik aanroep ofzo?

[ Voor 43% gewijzigd door ThinkPad op 28-08-2014 16:30 ]


  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Het lijkt me verstandig als je eerst dit aan de praat krijgt, voordat je gelijk nieuwe functionaliteit gaat toevoegen.

feature creep.

[ Voor 51% gewijzigd door RobV op 28-08-2014 17:22 ]

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


  • noo
  • Registratie: Januari 2012
  • Niet online

noo

ThinkPadd schreef op donderdag 28 augustus 2014 @ 16:29:

Hebben jullie toevallig ook nog een ingeving waarmee ik het actuele verbruik nog wel steeds om de 10sec eruit kan krijgen? (Waarde uitspugen als ik http://arduino?huidigverbruik aanroep ofzo?
Ja: stuur de data gewoon om de 10 seconden en los het aggregeren aan de database kant op door de data voor de betreffende minuuut in de database te updaten. Ik doe iets dergelijks voor upload naar PVoutput: ik lees mijn omvormer elke 5 seconden uit en heb een function in de database die met een simpel sommetje van de timestamp bepaalt in welk 5 minuten interval de data hoort en dan een upsert van het betreffende interval doet.

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
pv=> \sf timeslot
CREATE OR REPLACE FUNCTION public.timeslot(timestamp without time zone)
 RETURNS timestamp without time zone
 LANGUAGE sql
AS $function$
select date_trunc('hour', $1) + date_part('minute', $1)::int / 5 * interval '5 min' + interval '5 min';
$function$

pv=> \sf update_pvoutput 
CREATE OR REPLACE FUNCTION public.update_pvoutput(a_ts timestamp without time zone, a_v1 real, a_v2 real, a_v5 real, a_v7 real, a_v8 real, a_v9 real, a_v10 real, a_v11 real, a_v12 real)
 RETURNS void
 LANGUAGE plpgsql
AS $function$
begin
  loop
     update pvoutput set(v1, v2, v5, v7, v8, v9, v10, v11, v12, rc) = (a_v1, a_v2, a_v5, a_v7, a_v8, a_v9, a_v10, a_v11, a_v12, -1) where ts = (select timeslot(a_ts));
   if found then
     return;
   end if;
   begin
     insert into pvoutput(ts, v1, v2, v5, v7, v8, v9, v10, v11, v12, rc) values((select timeslot(a_ts)), a_v1, a_v2, a_v5, a_v7, a_v8, a_v9, a_v10, a_v11, a_v12, -1);
     return;
   exception when unique_violation then
     -- nothing, try again
   end;
  end loop;
end;
$function$

(PostgreSQL overigens, maar zoiets kan vast ook in MySQL)

[ Voor 0% gewijzigd door noo op 28-08-2014 21:22 . Reden: noo kan niet typen ]


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Ik weet niet, dat voelt voor mij een beetje als dweilen met de kraan open.

Het huidige verbruik met 10sec resolutie is ook alleen nodig om op een webpagina te tonen, verder doe ik daar niks mee. Zoals gezegd is in de grafiek een resolutie van 1 minuut (of 30sec, als 1 minuut te grof blijkt) genoeg in principe.

  • gekkie
  • Registratie: April 2000
  • Laatst online: 14:56
ThinkPadd schreef op donderdag 28 augustus 2014 @ 22:09:
Ik weet niet, dat voelt voor mij een beetje als dweilen met de kraan open.

Het huidige verbruik met 10sec resolutie is ook alleen nodig om op een webpagina te tonen, verder doe ik daar niks mee. Zoals gezegd is in de grafiek een resolutie van 1 minuut (of 30sec, als 1 minuut te grof blijkt) genoeg in principe.
huidige gebruik in een tekst bestandje dumpen en dan parsen door je webpagina, of een extra tabel in je DB met alleen het meest recente huidige gebruik ?

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Dat lukt op zich wel, maar ik zit meer met de Arduino code.

Denk dat ik dan 2 functies maak, eentje voor huidig verbruik uitspugen, welke om de 10sec draait (millis+10sec) (wat ik dan doe moet ik nog ff uitzoeken, misschien via HTTP als JSON, of dumpen in MySQL), en eentje voor de meterstanden, welke om de minuut draait (millis+1minuut).

  • gekkie
  • Registratie: April 2000
  • Laatst online: 14:56
ThinkPadd schreef op donderdag 28 augustus 2014 @ 23:30:
Dat lukt op zich wel, maar ik zit meer met de Arduino code.

Denk dat ik dan 2 functies maak, eentje voor huidig verbruik uitspugen, welke om de 10sec draait (millis+10sec) (wat ik dan doe moet ik nog ff uitzoeken, misschien via HTTP als JSON, of dumpen in MySQL), en eentje voor de meterstanden, welke om de minuut draait (millis+1minuut).
Ah ja .. in mijn perl baksel heb ik geen timer en interval .. script wacht gewoon tot de TTY weer een telegrammetje uitspuugt .. parsed en gaat dan weer lekker wachten, geen idee of dat in C makkelijk te bakken is :) (voordeel was vooral dat ik op deze manier nooit ergens halverwege een telegram inval en dus niet goed parsebaar resultaat krijg)

Maar goed in je huidige setup is het toch ook maar kwestie van een countertje .. na 6 keer een telegram counter op 0 en meterstanden in de db ...

[ Voor 7% gewijzigd door gekkie op 28-08-2014 23:37 ]


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Dat heb ik nu ook, dat hij wat gaat doen zodra er een nieuw telegram binnenkomt. Counter is misschien ook nog wel een idee ja. Dat als de counter 6 is de boel versturen.

Dat ik halve data ga parsen kom ik nu ook achter tijdens wat probeerdingetjes.

  • gekkie
  • Registratie: April 2000
  • Laatst online: 14:56
ThinkPadd schreef op donderdag 28 augustus 2014 @ 23:46:
Dat ik halve data ga parsen kom ik nu ook achter tijdens wat probeerdingetjes.
Hmm zou dan toch niet moeten mogen .. als je wacht op een telegram ..
scriptje van mij wacht specifiek op een match met het uitroepteken (einde bericht markering) .. en alles wat er dan nieuw is binnen gekomen sinds de vorige keer daar gaat tie mee aan de parse.

Is het niet handiger om je code te herschrijven zodat je meegaat in de cadans van de meter:
met een mainloop die serial uitleest totdat je een ! hebt, telegram is dan compleet en je hebt nu +/- 10 seconden om te parsen en weg te schrijven ... dus je hoeft ook niet echt moeilijk te doen met parallel lezen en parsen enzo.

[ Voor 26% gewijzigd door gekkie op 29-08-2014 00:03 ]


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Komt door de volgorde denk ik. Ik wacht een minuut en ga dan kijken of er wat te doen valt op de seriële poort. Dat moet anders denk ik.

Maar ben nu even aan het klooien met een counter, dat doet opzich ook wel wat ik wil, en is makkelijker in te bouwen. We weten immers dat de P1 poort elke 10sec wat uitspuugt. Opzich kun je daarmee de interval zo groot maken als je wilt, gewoon het aantal telegrammen tellen, en dan er eentje uitpakken die je wilt hebben (na xx tijd). Wil je elke minuut dan pak je het 6e telegram, wil je om de twee minuten dan pak je elk 12e telegram, etc.

Acties:
  • 0 Henk 'm!

  • gekkie
  • Registratie: April 2000
  • Laatst online: 14:56
ThinkPadd schreef op vrijdag 29 augustus 2014 @ 00:03:
Komt door de volgorde denk ik. Ik wacht een minuut en ga dan kijken of er wat te doen valt op de seriële poort. Dat moet anders denk ik.

Maar ben nu even aan het klooien met een counter, dat doet opzich ook wel wat ik wil, en is makkelijker in te bouwen. We weten immers dat de P1 poort elke 10sec wat uitspuugt. Opzich kun je daarmee de interval zo groot maken als je wilt, gewoon het aantal telegrammen tellen, en dan er eentje uitpakken die je wilt hebben (na xx tijd). Wil je elke minuut dan pak je het 6e telegram, wil je om de twee minuten dan pak je elk 12e telegram, etc.
Mjah volgens mij is serial uitlezen tot je het einde van telegram te pakken hebt het beste, eventueel kun je hem op basis van een counter of epoch wel of niet of gedeeltelijk parsen en opslaan.

Dan voorkom je het probleem dat je toevallig je programma hebt gestart in een cadans dat hij steeds midden in een telegram begint te lezen.

Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Uitlezen tot het einde doe ik sowieso.

Ik heb nu dit toegevoegd:
C++:
1
2
3
4
5
6
7
8
9
10
    if (input == '!') {   //uitroepteken geeft einde van telegram aan, dus we gaan data versturen
      counter = counter + 1; //increment the counter

      if (counter == 6) {
        counter = 0;
        httpRequest();  
      }      
      mEVLT = 0;
     [..nog wat andere meuk op 0 zetten, client.stop etc]
    }  


Dus hij ontvangt net als anders om de 10sec een bericht, maar pas bij het 6e bericht (na 6x10 sec = 1min) gaat hij het pas versturen.

Of is dat te simpel gedacht? Heb m'n MySQL database nog niet weer op de rit dus kan nog niet testen :P

Acties:
  • 0 Henk 'm!

  • gekkie
  • Registratie: April 2000
  • Laatst online: 14:56
ThinkPadd schreef op vrijdag 29 augustus 2014 @ 00:26:
Uitlezen tot het einde doe ik sowieso.
Ok .. nouja omdat je zei dat je ook wel eens halve berichten geparsed kreeg dacht ik van niet :)
Dus hij ontvangt net als anders om de 10sec een bericht, maar pas bij het 6e bericht (na 6x10 sec = 1min) gaat hij het pas versturen.

Of is dat te simpel gedacht? Heb m'n MySQL database nog niet weer op de rit dus kan nog niet testen :P
Alleen het huidige verbruik wou je toch buiten die counter houden en om de 10 seconden opslaan/overschrijven ? (ook best leuk om op te slaan hoor ... je kunt je apparaten redelijk herkennen ... waterkokers .. koffiezetter .. oven ..)

[ Voor 23% gewijzigd door gekkie op 29-08-2014 09:31 ]


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Ik heb het nu een poosje draaiend met de counter (als hij 6 berichten heeft ontvangen > versturen)

Je merkt alleen dat de metingen uit elkaar gaan lopen (nieuwste bovenaan):
code:
1
2
3
4
5
6
7
8
9
10
11
12
2014-08-29 19:26:16
2014-08-29 19:24:15
2014-08-29 19:23:14
2014-08-29 19:21:13
2014-08-29 19:16:11
2014-08-29 19:14:10
2014-08-29 19:13:09
2014-08-29 19:12:09
2014-08-29 19:11:08
2014-08-29 19:10:08
2014-08-29 19:07:06
2014-08-29 19:06:06


regel 10 t/m 6 gaat het goed, daarna gaat hij uit de pas lopen.

Op een gegeven moment gaat hij echter wel weer in de pas lopen:
code:
1
2
3
4
5
6
2014-08-29 19:46:26
2014-08-29 19:45:25
2014-08-29 19:44:25
2014-08-29 19:43:24
2014-08-29 19:42:24
2014-08-29 19:41:23

Ik denk dat het komt omdat hij de data gaat versturen, wat even duurt, en daarna weer verder gaat. Dit zorgt voor een kleine vertraging.

Misschien toch maar gewoon alles wat hij binnenkrijgt wegschrijven, en aan de database kant aggregeren :S
Of gewoon de hele sketch omgooien en het interval op de server regelen dmv cronjob:
- Elke 10sec actuele verbruik ophalen
- Elke minuut de elektra meterstanden ophalen
- Elk uur gasmeterstand ophalen

Beetje Youless idee, met verschillende URL's met JSON output data.

[ Voor 20% gewijzigd door ThinkPad op 29-08-2014 19:54 ]


Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Of je timing routine eventjes aanpassen. Nu reset je de teller NA het verzenden. Als je nu je teller reset VOOR het verzenden, heb je het opgelost.

Dus:

code:
1
2
3
4
5
6
if(millis() - lastTime > 60*1000U)
{
   lastTime = millis();

   //functieaanroep.
}

[ Voor 28% gewijzigd door RobV op 29-08-2014 19:55 ]

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Dat heb ik toch al?

C++:
1
2
3
4
      if (counter == 6) {
        counter = 0;
        httpRequest();  
                       }     

[ Voor 12% gewijzigd door ThinkPad op 29-08-2014 19:56 ]


Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
ThinkPadd schreef op vrijdag 29 augustus 2014 @ 19:55:
Dat heb ik toch al?

C++:
1
2
3
4
      if (counter == 6) {
        counter = 0;
        httpRequest();  
                                 }     
Nee dat is je counter, en niet je timing logic. Zie mijn edit ^^

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Millis gebruik ik niet (meer) :p

Nu gewoon bij elk eind van het bericht: counter + 1 en na het verzenden de counter weer op 0.
Zie ook gehele sketch hier: http://pastebin.com/gvhsT2zb (heb o.a. de loop kleiner gemaakt zoals hier als tip werd gegeven ;) )

Met millis werkte het ook wel, maar dan kreeg ik halve data, omdat als het tijd was om iets te doen ineens halverwege een telegram binnenviel. Dat is ook beetje het vervelende aan de meter, je kunt het niet zelf sturen, gewoon afwachten tot er weer 10sec voorbij zijn en er weer een bericht wordt uitgespuugd. Als je te laat begint met lezen dan mis je een aantal regels.

[ Voor 3% gewijzigd door ThinkPad op 29-08-2014 19:59 ]


Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Ok, leg mij eens uit hoe je dingen op een exacte timing wilt hebben als je de timing eruit gehaald hebt... 8)7

En over het opsplitsen van je functie:

code:
1
2
3
void loop() {
  decodeTelegram();
}


Daar schiet natuurlijk helemaal niemand iets mee op... Stop nou gewoon eens de body van de 'if(input == '\n') en de body van de 'if(input == '!')' in 2 aparte functies... Dan heb je het lezen en schrijven functioneel gescheiden. Een ander enorm voordeel is dat je dan lokale variabelen kunt gaan gebruiken zodat de een niet in de weg zit van de ander.

Een andere tip die ik je ga geven: stop met variabelenamen van 2 of 3 letters. We hebben hier een compiler die symbolen van 128 tekens aankan (of zo)... Noem de dingen gewoon wat ze zijn en wat ze doen: tl -> meterstandIntegerDeel, tld -> meterstandFractie.

'empty buffer' kan met een enkele regel: memset

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
RobV schreef op vrijdag 29 augustus 2014 @ 20:06:
Ok, leg mij eens uit hoe je dingen op een exacte timing wilt hebben als je de timing eruit gehaald hebt... 8)7
Goede. Zal nog eens gaan klooien met die millis idd. Kan ik dat gewoon ipv die 'counter == 6' doen zonder dat ik halve berichten ga binnenkrijgen?
En over het opsplitsen van je functie:

code:
1
2
3
void loop() {
  decodeTelegram();
}


Daar schiet natuurlijk helemaal niemand iets mee op... Stop nou gewoon eens de body van de 'if(input == '\n') en de body van de 'if(input == '!')' in 2 aparte functies... Dan heb je het lezen en schrijven functioneel gescheiden. Een ander enorm voordeel is dat je dan lokale variabelen kunt gaan gebruiken zodat de een niet in de weg zit van de ander.
Oke. Dus in de loop een functie aanroepen, en die functie roept weer een functie voor het lezen aan, en een functie voor het schrijven (de HTTP requests) aan
Een andere tip die ik je ga geven: stop met variabelenamen van 2 of 3 letters. We hebben hier een compiler die symbolen van 128 tekens aankan (of zo)... Noem de dingen gewoon wat ze zijn en wat ze doen: tl -> meterstandIntegerDeel, tld -> meterstandFractie.
Dit komt omdat ik de code voor het ontvangen en ontcijferen van een telegram uit de meter uit een andere sketch heb gepikt :P Zal er eens naar kijken, wordt het duidelijker van inderdaad.
'empty buffer' kan met een enkele regel: memset
Thanks, zal daar ook naar kijken.

Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
ThinkPadd schreef op vrijdag 29 augustus 2014 @ 20:18:
Oke. Dus in de loop een functie aanroepen, en die functie roept weer een functie voor het lezen aan, en een functie voor het schrijven (de HTTP requests) aan
Ik kan dit heel moeilijk uitleggen, dat moet je zelf een beetje aanvoelen. Net als bij het schrijven van een boek, ik kan je stijlfouten wel aanwijzen, maar je blijft zelf de auteur die de zinnetjes moet maken.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Dat is waar. Ik sta er ook wel voor open, maar het is mij niet exact duidelijk wat je bedoelt.
Naar mijn idee heb ik de code nu al aardig in stukken opgebroken. Dat 'if counter == xxxx' stukje kan wellicht nog wat verder, maar verder zie ik het zo niet.

[ Voor 45% gewijzigd door ThinkPad op 29-08-2014 20:29 ]


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Ik ben nog steeds bezig om de uitlees interval op 1 minuut te krijgen dmv 'millis', maar het wil niet lukken :/

Er wordt gewoon niks bijgeschreven in de database. Als ik het millis gebeuren eruit sloop en 'decodeTelegram()' in de loop telkens aanroep dan werkt het wel....

Moet ik de if (altSerial.available()) { misschien wel in de normale loop, en alleen de HTTP aanroep functie in de millis?

Ik kom er even niet meer uit....

Ik heb deze code:
C++:
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <AltSoftSerial.h>
#include <SPI.h>
#include <Ethernet.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;

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0x30, 0x32, 0x31};
IPAddress ip(192,168,4,7);
IPAddress server(192,168,4,4);
EthernetClient client;

const int requestPin =  4;         
char input; // incoming serial data (byte)
bool readnextLine = false;
#define BUFSIZE 75
char buffer[BUFSIZE]; //Buffer for serial data to find \n .
int bufpos = 0;
long mEVLT = 0; //Meter reading Electrics - consumption low tariff
long mEAV = 0;  //Meter reading Electrics - Actual consumption
long mG = 0;   //Meter reading Gas

long lastTime = 0;        // will store last time LED was updated
long interval = 60000;           // interval at which to blink (milliseconds)

void setup() {
  Serial.begin(9600);
  delay(1000);

  altSerial.begin(115200);
  delay(1000);

  Ethernet.begin(mac, ip);
  delay(1000);
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
  Serial.print("Server IP address: ");
  Serial.println(server);

  pinMode(4, OUTPUT);                  // SD select pin
  digitalWrite(4, HIGH);               // Explicitly disable SD

  //Set RTS pin high, so smart meter will start sending telegrams
  pinMode(requestPin, OUTPUT);
  digitalWrite(requestPin, HIGH);
}

void loop() {

  if(millis() - lastTime > interval) {
    // save the last time you blinked the LED 
    lastTime = millis();   

    decodeTelegram();
  }



} //Einde loop

void decodeTelegram() {
  long tl = 0;
  long tld =0;

  if (altSerial.available()) {
    input = altSerial.read();

    char inChar = (char)input;
    // Fill buffer up to and including a new line (\n)
    buffer[bufpos] = input&127;
    bufpos++;

    if (input == '\n') { // We received a new line (data up to \n)
      if (sscanf(buffer,"1-0:1.8.1(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEVLT = tl;
        if (mEVLT > 0) {
          Serial.println("*** BEGIN LOOP ***");
          Serial.print("Elektra - meterstand verbruik LAAG tarief: ");
          Serial.println(mEVLT);

        }
      }

      // 1-0:1.7.0 = Electricity consumption actual usage (DSMR v4.0)
      if (sscanf(buffer,"1-0:1.7.0(%ld.%ld" ,&tl , &tld) == 2)
      { 
        mEAV = (tl*1000)+tld;
        if (mEAV > 0) {
          Serial.print("Elektra - actueel verbruik (W): ");
          Serial.println(mEAV);
        }
      }

      // 0-1:24.2.1 = Gas (DSMR v4.0) on Kaifa MA105 meter
      if (strncmp(buffer, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0) {
        if (sscanf(strrchr(buffer, '(') + 1, "%d.%d", &tl, &tld) == 2) {
          mG = (tl*1000)+tld; 
          Serial.print("Gas - meterstand (liters): ");
          Serial.println(mG);
          Serial.println("");
        }
      }

      // Empty buffer again (whole array)
      for (int i=0; i<75; i++)
      { 
        buffer[i] = 0;
      }
      bufpos = 0;

    }

    if (input == '!') {   //uitroepteken geeft einde van telegram aan, dus we gaan data versturen
      httpRequest();
      mEVLT = 0;
      mEAV = 0;
      mG = 0;
      client.stop();
    } //Einde vraagteken detectie   

  } //Einde 'if AltSerial.available'

} //Einde 'decodeTelegram()' functie

void httpRequest() {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    client.print("GET /www/slimmemeter/p1.php?mEVLT=");
    client.print(mEVLT);
    client.print("&mEAV=");
    client.print(mEAV);
    client.print("&mG=");
    client.print(mG);
    client.println(" HTTP/1.1");
    client.println("Host: 192.168.4.4");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();
    //Request complete; empty recieve buffer
    while (client.available()) { //data available
      char c = client.read(); //gets byte from ethernet buffer
    }
    client.println();
    Serial.println("----------------------------Versturen naar database--------------------------");
    Serial.println("Connection OK!");
    Serial.print("GET /www/slimmemeter/p1.php?mEVLT=");
    Serial.print(mEVLT);
    Serial.print("&mEAV=");
    Serial.print(mEAV);
    Serial.print("&mG=");
    Serial.println(mG);
    Serial.println("-----------------------------------------------------------------------------");
    Serial.println();
    Serial.println("*** EINDE LOOP - Wachten op volgende telegram vanuit slimme meter ***");
  } 
  else {
    Serial.println("Connection failed");
    client.stop();
  }
}

Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Wat je nu hebt, is dat je maar 1x per minuut de serial port uitleest. Verder klopt het wel, want je verstuurt ieder telegram dat je ontvangen hebt via http.

Als je nou wilt dat je ieder telegram accepteert, maar alleen de laatste elke 60 seconden verstuurt naar de DB, dan moet je de serial.available() buiten je timer lus halen.

Ik wilde tot slot nog even zeggen dat je flink gegroeid bent. De code is goed leesbaar.Ik mis alleen nog de header met de beschrijving van wat de sketch doet en wie hem gemaakt heeft.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Kijk, zoiets dacht ik al. Maar toch even navragen ;)
Ik ga vanavond nog even weer knutselen.

En dankjewel :$ Ik begin het nu een beetje te snappen hoe het werkt. Ook heb ik door eigen knutselen (en wat hulp van hier _o_ ) resultaat verkregen, wat natuurlijk altijd leuk is.

Ik heb trouwens nog gekeken of ik de namen van de variabelen (die 'tl' en 'tld') duidelijker kon krijgen. Maar daarna stopte de sketch na een stuk of 5 wegschrijf acties ineens met werken. Nog maar even weer checken, want als ik de naam van de variabele overal meewijzig moet dat het probleem immers niet zijn.

Edit: Yay, gelukt *O* (vanaf id 22156, daarvoor was nog met oude sketch)
+-------+---------------------+-------------+-----------------+-------+
| id | time | laag_tarief | huidig_verbruik | gas |
+-------+---------------------+-------------+-----------------+-------+
| 22165 | 2014-09-02 17:36:53 | 59.349 | 52 | 6.121 |
| 22164 | 2014-09-02 17:35:53 | 59.348 | 52 | 6.121 |
| 22163 | 2014-09-02 17:34:53 | 59.348 | 51 | 6.121 |
| 22162 | 2014-09-02 17:33:53 | 59.347 | 51 | 6.121 |
| 22161 | 2014-09-02 17:32:53 | 59.346 | 52 | 6.121 |
| 22160 | 2014-09-02 17:31:53 | 59.345 | 51 | 6.121 |
| 22159 | 2014-09-02 17:30:53 | 59.344 | 52 | 6.121 |
| 22156 | 2014-09-02 17:29:43 | 59.343 | 51 | 6.121 |
| 22155 | 2014-09-02 17:20:30 | 59.335 | 51 | 6.121 |
| 22154 | 2014-09-02 17:20:10 | 59.335 | 52 | 6.121 |
+-------+---------------------+-------------+-----------------+-------+


Definitieve code hier: http://pastebin.com/gvhsT2zb (anders wordt het topic zo snel lang :p )

Ben wel benieuwd of de waardes nu ook beter kloppen, soms was de meterstand ineens 0 bijv. Met PHP gooide ik direct na INSERT de foutieve rows weer weg, zal dat er nu als test even uithalen en hem de hele avond laten lopen, kijken wat ie doet :Y

Nee dus, nog steeds glippen er soms enorm hoge waardes door }:|
+-------+---------------------+-------------+-----------------+--------+
| id | time | laag_tarief | huidig_verbruik | gas |
+-------+---------------------+-------------+-----------------+--------+
| 22818 | 2014-09-03 04:20:19 | 60.235 | 53 | 6.398 |
| 22819 | 2014-09-03 04:21:19 | 999.999 | 1831483449 | 99.999 |
| 22820 | 2014-09-03 04:22:19 | 60.237 | 53 | 6.398 |
+-------+---------------------+-------------+-----------------+--------+

Weet iemand hoe ik dat kan vermijden? Ik wil de gasmeterstanden automatisch laten uploaden naar Mindergas.nl, maar dan moeten ze wel betrouwbaar zijn natuurlijk :/

Ik kan wel zelf wat in het PHP upload script gaan afvangen, maar netter is het om het bij de bron op te lossen... Iemand tips?

[ Voor 76% gewijzigd door ThinkPad op 03-09-2014 07:26 ]


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Iemand nog een idee hoe ik de uitlezing betrouwbaarder kan krijgen?

En ik zoek nog een idee om het huidige verbruik wel met een interval van 10s uit de Arduino te krijgen, zonder MySQL steeds lastig te vragen. Ik zat te denken aan een URL op de Arduino aan te roepen. De waarde wordt alleen als tekst getoond op een webpagina, hoeft verder niet opgeslagen te worden.

[ Voor 37% gewijzigd door ThinkPad op 05-09-2014 14:43 ]


Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Houdt een running average bij. Even googlen voor de formule, hij is erg eenvoudig. Als er dan een waarde is die meer dan 50% afwijkt van het gemiddelde kan je er redelijk vanuit gaan dat het een bogus is.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Thanks, dat klinkt opzich wel handig. Maar verbruik kan natuurlijk flink heen en weer vliegen terwijl het wel klopt... Rustverbruik van 50W, en wanneer ik de oven aanzet ineens 2200W. Dan is dat niet heel handig....

Ik hoop eigenlijk ergens iets in de code te kunnen wijzigen (delay in het uitlezen toevoegen bijv.) waardoor het beter gaat. Ik snap namelijk niet goed waar die hoge waarden vandaan komen (te snel uit willen lezen, half uitlezen van telegram?)

[ Voor 5% gewijzigd door ThinkPad op 05-09-2014 14:48 ]


Acties:
  • 0 Henk 'm!

  • Proton_
  • Registratie: November 2011
  • Nu online

Proton_

Moderator Wonen & Mobiliteit 

Team Welles

99.999 klinkt niet als een parsefout of ruis op de lijn... in je code is er ook niets dat de waarden zo initialiseert, dan zouden ze uit de meter zelf komen :?

Om te testen kan je misschien het hele telegram ook naar de database loggen?

Het ik-wil-een-warmtepomp FAQ topic- '23 MG5, douchen met wtw en Auer Edel Eau, verwarming met Vaillant Arotherm Plus.


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Die 99.999 komt door het datatype wat ik voor die kolom heb ingevuld. Het huidig verbruik is een INT, en dan pleurt ie er gewoon een enorm getal in. Dat 'past' niet in de kolom, dus wordt het het grootste getal wat wel past, 99.999. Voorheen bij de andere kolommmen was het ook iets van 123123902012 ofzo ipv 99.999 (toen ik alles nog op VARCHAR had staan).

Hij gooit er meestal gewoon de goede waarde in, maar af en toe is het '0' of een enorm hoge waarde.

En hoe moet ik een telegram van meerdere regels in de database proppen :P ?

[ Voor 12% gewijzigd door ThinkPad op 05-09-2014 16:16 ]


Acties:
  • 0 Henk 'm!

  • noo
  • Registratie: Januari 2012
  • Niet online

noo

ThinkPadd schreef op vrijdag 05 september 2014 @ 16:13:
Die 99.999 komt door het datatype wat ik voor die kolom heb ingevuld. Het huidig verbruik is een INT, en dan pleurt ie er gewoon een enorm getal in. Dat 'past' niet in de kolom, dus wordt het het grootste getal wat wel past, 99.999. Voorheen bij de andere kolommmen was het ook iets van 123123902012 ofzo ipv 99.999 (toen ik alles nog op VARCHAR had staan).

Hij gooit er meestal gewoon de goede waarde in, maar af en toe is het '0' of een enorm hoge waarde.

En hoe moet ik een telegram van meerdere regels in de database proppen :P ?
Je logt de waardes al in je parse loop naar de seriele poort, zijn ze dan nog wel allemaal zinnig? (maw: zit de fout in je sketch of onderweg naar de database?)

Acties:
  • 0 Henk 'm!

  • Willie Wortel
  • Registratie: Maart 2012
  • Niet online
Vreemde logwaarden? Als je een zwakke voeding hebt voor je Arduino en de voeding staat op dezelfde groep waarvan je plots een hoog ampèrage trekt kan die "glitch" in je data de mogelijke oorzaak zijn.

Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
noo schreef op vrijdag 05 september 2014 @ 16:38:
[...]

Je logt de waardes al in je parse loop naar de seriele poort, zijn ze dan nog wel allemaal zinnig? (maw: zit de fout in je sketch of onderweg naar de database?)
Ik zal m'n laptop er eens aan hangen, en kijken wat ik dan voorbij zie komen. Ik heb zo'n idee dat het onderweg naar de database gebeurt. Eerder toen ik nog aan het prutsen was om de juiste waardes eruit te trekken, en ik m'n laptop er ook aan had hangen om de output te bekijken heb ik nooit zulke hoge waarden voorbij zien komen.
Willie Wortel schreef op vrijdag 05 september 2014 @ 20:30:
Vreemde logwaarden? Als je een zwakke voeding hebt voor je Arduino en de voeding staat op dezelfde groep waarvan je plots een hoog ampèrage trekt kan die "glitch" in je data de mogelijke oorzaak zijn.
Dat lijkt mij niet het probleem. De voeding is een 5V 1A USB adapter van goede kwaliteit, hij werd bij m'n Nexus 5 geleverd. Geen 1 euro voeding van de Action ofzo dus ;)

Het is ook niet dat het altijd extreem hoge waarden zijn, soms is het een waarde die er op het eerste gezicht prima uitziet. Vergelijk je hem dan echter met waardes van een minuut eerder, of een minuut later, dan zie je dat het niet klopt (gasverbruik wordt maar 1x per uur geupdate door de meter)

+---------------------+-------+
| time | gas |
+---------------------+-------+
| 2014-09-06 06:13:20 | 7.647 |
| 2014-09-06 06:14:20 | 7.006 |
| 2014-09-06 06:15:20 | 7.647 |
| 2014-09-06 06:16:20 | 7.647 |
| 2014-09-06 06:17:20 | 7.647 |
+---------------------+-------+

[ Voor 24% gewijzigd door ThinkPad op 06-09-2014 10:11 ]


Acties:
  • 0 Henk 'm!

  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Ik vind het sowieso al knap dat je het voor elkaar krijgt om de serial poort met 115200 uit te lezen. Ik krijg zelf nooit iets stabiel boven de 14400.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Daarom gebruik ik dus de AltSoftSerial library, met de standaard SoftwareSerial was het drama, daarmee kreeg ik boven de 9600 baud halve data of verminkte data binnen. Als je meer betrouwbare serial nodig hebt dan is dat de moeite wel waard om eens naar te kijken.

Beste is hardware serial, maar dat is onhandig, dan kun je niet met USB kijken wat hij uitspuugt bijv.
En ik moet de poort wel met 115200 baud uitlezen, dat is nou eenmaal de snelheid waarop hij werkt :P Er zit geen jumper op de meter om het naar een lagere snelheid ofzo te zetten :+

Ik heb nu 2x een kleine delay toegevoegd, op regel 83 & 178 (beiden 500ms). Zal hem nu even weer een dag laten lopen, kijken of het helpt. Ook in de setup() nog even de volgorde van initialiseren gewijzigd. Eerst Ethernet, dan AltSerial, dan Serial (op volgorde van belangrijkheid).

Edit: Helpt niet ;(

[ Voor 60% gewijzigd door ThinkPad op 06-09-2014 12:07 ]


Acties:
  • 0 Henk 'm!

  • Willie Wortel
  • Registratie: Maart 2012
  • Niet online
De baudrate moet identiek zijn tussen zender ~ ontvanger, deze is bij de slimme meter naar mijn weten 9600 baud. Kijk even in de specs van je meter. Is deze 9600, ga dan niet experimenteren met een andere waarde want dat is dan niet juist.

Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Bij mij is het echt 115200, met 9600 krijg ik er alleen maar rotzooi uit.

Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Moest een kleine aanpassing doen aan de code, blijkbaar telt m'n meter op 2 telwerken, terwijl ik er eerst maar eentje uit las. Slimme meter altijd hoog/laag tarief ipv enkeltarief?

Verder draait de Arduino nu een tijd, maar ik ben er niet helemaal tevreden over. Ik vind de oplossing niet heel betrouwbaar werken. Ik krijg nog steeds om de zoveel tijd allemaal crap waarden binnen. Ik heb in de PHP code die het in de database gooit al wat toegevoegd zodat de crap zoveel mogelijk in een aparte tabel wordt gegooid (voor latere debugging), maar toch raakt m'n hoofd tabel wel steeds weer vervuild met verkeerde data. De meterstand is dan bijv. een hele tijd 108.765 en is dan ineens 108.767 Niks mis mee zou je zeggen, ware het niet dat hij daarna gewoon weer 108.765 binnenkrijgt. Oftewel het klopt niet. En zulke kleine afwijkingen zijn ook niet in de code eruit te filteren...

Daar baal ik best wel van, en ik twijfel of ik wel met de Arduino verder wil in deze uitlees oplossing. Misschien eens met een Pi proberen, en dan alsnog in MySQL gooien. Punt is namelijk dat ik de data gewoon (meer) betrouwbaar wil hebben. Ik wil dagtotalen berekenen, en ik upload de gasmeterstanden dagelijks naar mindergas.nl. Dan wil ik niet van die rotzooi in m'n tabellen hebben :S

[ Voor 3% gewijzigd door ThinkPad op 16-09-2014 21:44 ]


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Wat ik mij ook nog bedacht (soms moet je iets gewoon even laten rusten en er even een poosje over nadenken :Y) ), is dat ik de output van de meter constant enabled heb (door +5V op de RTS pin te zetten).

Gevolg is dat er elke 10s data binnenkomt. De Arduino moet dus elke 10s deze data weer begrijpelijk maken (decodeTelegram();). Ook als ik de data ga versturen kan het voorkomen dat de Arduino daarmee bezig is. Wellicht dat dit de rare waardes verklaart.

Ook zet ik de variabelen na het versturen weer op 0, maar voordat ik de data heb verstuurd zijn die variabelen al wel een keer of 6x overschreven (elke 10s output van meter = 6x in een minuut overschreven).

Ik kreeg daarom het volgende ingenieuze idee:
  1. Is er weer een minuut verstreken?
  2. RTS hoog
  3. Data ontvangen
  4. RTS laag
  5. Data versturen
Volgens mij spuugt de meter gelijk een telegram uit zodra je hem 'wakker' maakt door RTS hoog te maken.

Op die manier hoeft de Arduino zich tijdens het versturen van de data dus niet bezig te houden met het uitlezen van de meter. Dat heeft hopelijk als resultaat meer betrouwbare waarden.

Als ik tijd heb ga ik dat eens proberen :) Zou er dan zo uitzien:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void loop() {
  if(millis() - lastTime > interval) {
    lastTime = millis();   

    digitalWrite(requestPin, HIGH);
    decodeTelegram();
    digitalWrite(requestPin, LOW);
    //send data to PHP/MySQL
    httpRequest();
    //Reset variables to zero for next run
    mEVLT = 0;
    mEVHT = 0;
    mEAV = 0;
    mG = 0;
    //Stop Ethernet
    client.stop();
  }
} //Einde loop



Edit: Werkt niet :( Verdorie ;( Elke keer als het millis lusje loopt dan zie ik in de URL (via Serial Monitor) alleen maar 0 staan op de plek van de variabelen

Voor nu de originele sketch nog in gebruik, maar ipv AltSoftSerial nu aan de echte hardware serial (pin 0, RX) van de Duemilanove geknoopt. Eens kijken wat dat voor resultaten oplevert.

[ Voor 84% gewijzigd door ThinkPad op 17-09-2014 21:59 ]


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Ik denk dat ik voorzichtig (en misschien te voorbarig) de conclusie kan trekken dat het gebruiken van de hardware serial (pin 0, RX) de oplossing is om niet kloppende waarden tegen te gaan. Gisteravond rond 21:00 de aanpassing van AltSoftSerial (pin 8 ) naar hardware serial (pin 0) gedaan, en tot nu toe nog niet één verkeerde waarde doorgekregen _O_

Ik vermoed dat het komt omdat de hardware serial een UART is, die is voorzien van een hardware buffer. Daardoor hoeft de Arduino zich daar niet mee bezig te houden en verloopt het nu vlekkeloos

Ik dacht eerst dat je de hardware serial niet kon gebruiken als je de Arduino via USB voedt, maar dat zou volgens een bron op internet geen invloed moeten hebben. En dat klopt inderdaad. Ik voed de Arduino nu via USB, maar lees wel een serial device uit via pin 0 (RX), waar ook de FTDI chip van de USB/Serial aan hangt.

* ThinkPad happy *O*

[ Voor 21% gewijzigd door ThinkPad op 18-09-2014 17:55 ]


  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
De hardware serial is alleen aan de USB gekoppeld tijdens het uploaden van een sketch. Door de juiste pulsen te geven na een reset neemt herkent de bootloader dat er geupload wordt en neemt hij de controle van de UART op zich. Daarna is de serial wel weer vrij. Let wel op dat je geen Serial.println meer gebruikt want die gaan gewoon over de hardware serial, omdat 'ie denkt dat daar een USB aan hangt.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Klopt, ik heb alle Serial.print eruit gesloopt :)

C++:
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* Arduino 'slimme meter' P1 port reader.
 
 This sketch reads data from a Dutch smart meter that is equipped with a P1 port.
 Connect 'RTS' from meter to Arduino pin 5
 Connect 'GND' from meter to Arduino GND
 Connect 'RxD' from meter to Arduino pin 0 (RX)
 
 Baudrate 115200, 8N1.
 BS170 transistor & 10k resistor is needed to make data readable if meter spits out inverted data
 
 A .php file is requested (with consumption numbers in the GET request) every minute (interval set at line #52)
 created by 'ThinkPad' @ Tweakers.net, september 2014
 
 http://gathering.tweakers.net/forum/list_messages/1601301
 */

#include <AltSoftSerial.h>
#include <SPI.h>
#include <Ethernet.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

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0x30, 0x32, 0x31};
IPAddress ip(192,168,4,7);
IPAddress server(192,168,4,4);
EthernetClient client;

const int requestPin =  5;         
char input; // incoming serial data (byte)
bool readnextLine = false;
#define BUFSIZE 75
char buffer[BUFSIZE]; //Buffer for serial data to find \n .
int bufpos = 0;
long mEVLT = 0; //Meter reading Electrics - consumption low tariff
long mEVHT = 0; //Meter reading Electrics - consumption high tariff
long mEAV = 0;  //Meter reading Electrics - Actual consumption
long mG = 0;   //Meter reading Gas

long lastTime = 0;        // will store last time 
long interval = 60000;           // interval at which to blink (milliseconds)

void setup() {
  Serial.begin(115200);
  delay(1000);
  Ethernet.begin(mac, ip);
  delay(1000);
  pinMode(4, OUTPUT);                  // SD select pin
  digitalWrite(4, HIGH);               // Explicitly disable SD

  //Set RTS pin high, so smart meter will start sending telegrams
  pinMode(requestPin, OUTPUT);
  digitalWrite(requestPin, HIGH);
}

void loop() {

  decodeTelegram();

  if(millis() - lastTime > interval) {
    lastTime = millis();   
    //send data to PHP/MySQL
    httpRequest();
    //Reset variables to zero for next run
    mEVLT = 0;
    mEVHT = 0;
    mEAV = 0;
    mG = 0;
    //Stop Ethernet
    client.stop();
  }
} //Einde loop

void decodeTelegram() {
  long tl = 0;
  long tld =0;

  if (Serial.available()) {
    input = Serial.read();
    char inChar = (char)input;
    // Fill buffer up to and including a new line (\n)
    buffer[bufpos] = input&127;
    bufpos++;

    if (input == '\n') { // We received a new line (data up to \n)
      if (sscanf(buffer,"1-0:1.8.1(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEVLT = tl;
      }

      // 1-0:1.8.2 = Elektra verbruik hoog tarief (DSMR v4.0)
      if (sscanf(buffer,"1-0:1.8.2(%ld.%ld" ,&tl, &tld)==2){
        tl *= 1000;
        tl += tld;
        mEVHT = tl;
      }

      // 1-0:1.7.0 = Electricity consumption actual usage (DSMR v4.0)
      if (sscanf(buffer,"1-0:1.7.0(%ld.%ld" ,&tl , &tld) == 2)
      { 
        mEAV = (tl*1000)+tld;
      }

      // 0-1:24.2.1 = Gas (DSMR v4.0) on Kaifa MA105 meter
      if (strncmp(buffer, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0) {
        if (sscanf(strrchr(buffer, '(') + 1, "%d.%d", &tl, &tld) == 2) {
          mG = (tl*1000)+tld; 
        }
      }

      // Empty buffer again (whole array)
      for (int i=0; i<75; i++)
      { 
        buffer[i] = 0;
      }
      bufpos = 0;
    }
  } //Einde 'if AltSerial.available'
} //Einde 'decodeTelegram()' functie

void httpRequest() {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    client.print("GET /www/slimmemeter/p1.php?mEVLT=");
    client.print(mEVLT);
    client.print("&mEVHT=");
    client.print(mEVHT);
    client.print("&mEAV=");
    client.print(mEAV);
    client.print("&mG=");
    client.print(mG);
    client.println(" HTTP/1.1");
    client.println("Host: 192.168.4.4");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();
    //Request complete; empty recieve buffer
    while (client.available()) { //data available
      char c = client.read(); //gets byte from ethernet buffer
    }
    client.println();
  } 
  else {
    client.stop();
  }
}

[ Voor 3% gewijzigd door ThinkPad op 18-09-2014 19:33 ]


Anoniem: 621890

Hallo,

Ik ben een tweedejaars elektro student en heb als project gekregen om een systeem te bedenken ipv met energiemanagement. Ik heb beginners ervaring met programmeren en volg dit topic al een aantal dagen om kennis op te doen. Ik ben alleen niet van plan om echt een slimme meter aan te schaffen, maar te simuleren/testen op de manier hoe jij het hebt gedaan (via de arduino nano).

Echter is mijn vraag via welke aansluitingen je de Arduino en de nano hebt verbonden?

Ook zie ik dat je bepaalde headerfiles include in je programma, heb je daar ook nog de code pagina's van op het moment dat je nog aan het testen was via de nano?

Ik ben niet van de copy/paste, maar heb de interesse om me hierin te verdiepen en zelf toe te passen.

Ik zou het echt heel erg waarderen.

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Hoi,

De P1 dummy Arduino heb ik gemaakt met deze code: http://pastebin.com/rhfg0KWk
De AltSoftSerial library die ik gebruikte kun je hier vinden: https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html bij de Duemilanove zat de AltSoftSerial RX pin op pin 8. Voor andere Arduino's moet je even zoeken op die pagina.

Maar hardware serial werkt dus stabieler, en is makkelijker, daar hoef je verder ook geen extra libraries voor te includen ;)

Mocht je verder nog vragen hebben dan gelieve via een DM of even een eigen topic starten.

En wat mijn grote vriend hieronder zegt ;)

[ Voor 4% gewijzigd door ThinkPad op 18-09-2014 19:57 ]


  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
@Philippas, die header files zijn onderdeel van de Arduino toolkit, en eventuele nonstandard libs kun je gewoon vinden op de Arduino Playground. Daar is geen rocket science mee gemoeid.

Voordat je hieraan begint stel ik voor dat je gewoon eerste de Arduino tutorials doorloopt. Dat scheelt ons een hoop uitleggen en al je vragen als beginner worden daar prima uitgelegd. Kijk ook op het Arduino forum, er is zelfs een Nederlands topic (maar ik neem aan dat je als Electro student geen enkele moeite hebt met Engels.)

De bovenstaande code van Thinkpad heeft al een paar updates gehad en verschillende rondes aan bugfixes en 'grammar cop'-commentaar van robv (ik dus). Mijn complimentjes overigens aan Thinkpad voor de opmaak en het commentaar zoals het nu geworden is.

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


  • Raven
  • Registratie: November 2004
  • Niet online

Raven

Marion Raven fan

RobV schreef op donderdag 18 september 2014 @ 19:09:
De hardware serial is alleen aan de USB gekoppeld tijdens het uploaden van een sketch. Door de juiste pulsen te geven na een reset neemt herkent de bootloader dat er geupload wordt en neemt hij de controle van de UART op zich. Daarna is de serial wel weer vrij. Let wel op dat je geen Serial.println meer gebruikt want die gaan gewoon over de hardware serial, omdat 'ie denkt dat daar een USB aan hangt.
Kun je die niet gebruiken dan? Ik dacht altijd dat je tijdens het uploaden van de sketch de tx en rx pinnen moest loskoppelen, maar dat die daarna gewoon met serial.println gebruikt kunnen worden.

After the first glass you see things as you wish they were. After the second you see things as they are not. Finally you see things as they really are, and that is the most horrible thing in the world...

Oscar Wilde


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Still goin' strong zonder rare meetwaardes *O*

Ondertussen nog wat PHP scriptjes geschreven om o.a. dagtotaal weg te schrijven naar een tabel elke avond (cronjob om 23:59). Zelfde voor maandtotaal.

Die data toon ik vervolgens weer met wat mooie Highcharts staafgrafiekjes. En gasverbruik gaat ook iedere avond automatisch naar Mindergas.nl
Zal de code van de scriptjes vanavond even hier posten, zit nu op m'n werk.

* ThinkPad happy

Dingen waar ik ooit nog een keer naar wil kijken als ik tijd heb (nu niet ivm afstuderen):
  • Watchdog implementeren voor auto-reset bij rariteiten, zodat hij echt 24/7/365 kan loggen zonder aandacht eraan te schenken.
  • Code iets efficiënter maken, hij ontvangt nu nog 6x per minuut de verbruikswaardes, is niet nodig in principe. Dan is de Arduino meer idle, scheelt ook in stroomverbruik/warmte (die al zeer gering is bij Arduino)

[ Voor 52% gewijzigd door ThinkPad op 24-09-2014 11:12 ]


  • .SnifraM
  • Registratie: December 2012
  • Niet online
ThinkPadd schreef op woensdag 24 september 2014 @ 11:01:
Still goin' strong zonder rare meetwaardes *O*

Ondertussen nog wat PHP scriptjes geschreven om o.a. dagtotaal weg te schrijven naar een tabel elke avond (cronjob om 23:59). Zelfde voor maandtotaal.

Die data toon ik vervolgens weer met wat mooie Highcharts staafgrafiekjes.
Zal de code van de scriptjes vanavond even hier posten, zit nu op m'n werk.

* ThinkPad happy
Thanks, die wil ik ook hebben :) _/-\o_

lol+lol=hihi


  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
Ja, want de bedoeling is minder verbruiken en niet méér

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


  • gekkie
  • Registratie: April 2000
  • Laatst online: 14:56
RobV schreef op woensdag 24 september 2014 @ 11:31:
Ja, want de bedoeling is minder verbruiken en niet méér
Kan ik beter 1 keer in het jaar minder de waterkoker, koffieperser of oven gebruiken :)
(ik gebruik alleen een arduino bluetoothshield zonder arduino, geen idee hoeveel watt dat eet eigenlijk)

Maar opzich wel grappig om te zien dat je op basis van het huidige verbruik inderdaad na verloop van tijd aardig kunt inschatten wat je op een bepaald moment gedaan hebt op basis van de spikes in de chart.

Net als in mijn matig geisoleerde huis de vakanties er qua gasgebruik aardig uitspringen in de S-curve.
ThinkPadd schreef op woensdag 24 september 2014 @ 11:01:
Still goin' strong zonder rare meetwaardes *O*

* ThinkPad happy
Mooi dat het toch gelukt is en dat je het gevonden hebt als een hardware issue .. had je nog lang aan kunnen prutsen aan de software kant zonder effect :)

[ Voor 50% gewijzigd door gekkie op 24-09-2014 11:52 ]


  • RobV
  • Registratie: Juni 2013
  • Niet online

RobV

Welcome to the grid, Program.

(overleden)
jammer dan je PC wel altijd aan moet staan om de eaarden te loggen, en data versturen kost powerrr. Wellicht een ideetje om elke 30 minuten te flushen en tussendoor de waarden op iets als een SD kaartje te zetten als de webserver niet brnaderbaar is?

 | Mijn joystick / simpit project | Blog | Elite Dangerous CMDR Cataclysm72


  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Ik schrijf de data naar m'n NAS, die 24/7 draait (15W).
SD zou nog een optie kunnen zijn, maar volgens mij is dat niet stabiel. Lees iig veel problemen daarover.

Hierbij ook de scripts om de dagtotalen, maandtotalen te berekenen, en om staafgrafieken per dag van elke maand te tonen:

dagtotaal.php
PHP:
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
<?php
error_reporting(E_ALL);

//Connect to database
$MyUsername = "p1logger";  // enter your username for mysql
$MyPassword = "p1logger";  // enter your password for mysql
$MyHostname = "localhost";      // this is usually "localhost" unless your database resides on a different server

$dbh = mysql_pconnect($MyHostname , $MyUsername, $MyPassword);
$selected = mysql_select_db("p1",$dbh);

$query = mysql_query("SELECT (MAX(hoog_tarief)-MIN(hoog_tarief)) as e_hoog, (MAX(laag_tarief)-MIN(laag_tarief)) as e_laag, ((MAX(hoog_tarief)-MIN(hoog_tarief))+(MAX(laag_tarief)-MIN(laag_tarief))) as e_totaal, (MAX(gas)-MIN(gas)) as dagverbruik_g FROM p1.readings WHERE DATE(time) = CURRENT_DATE");
$row = mysql_fetch_array($query);
$e_hoog = $row[0]/1000;
$e_laag = $row[1]/1000;
$e_totaal = $row[2]/1000;
$dagverbruik_g = $row[3]/1000;
settype($e_hoog, "float");
settype($e_laag, "float");
settype($e_totaal, "float");
settype($dagverbruik_g, "float");

//Bereken totaal en schrijf weg naar 'dagtotalen' tabel
$SQL = "INSERT INTO p1.dagtotalen (id, time, e_hoog, e_laag, e_totaal, verbruik_g) VALUES (NULL, NULL, '".$e_hoog."', '".$e_laag."', '".$e_totaal."','".$dagverbruik_g."')"; 

//Voer bovenstaande query uit
mysql_query($SQL);

?>




maandtotaal.php
PHP:
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
<?php
error_reporting(E_ALL);

//Connect to database
$MyUsername = "p1logger";  // enter your username for mysql
$MyPassword = "p1logger";  // enter your password for mysql
$MyHostname = "localhost";      // this is usually "localhost" unless your database resides on a different server

if ( date('j') == date('t') ) { //Date 'j' is current daynumber of month. Date 't' is amount of days in month, this equation ensures query is only ran at last day of month

$dbh = mysql_pconnect($MyHostname , $MyUsername, $MyPassword);
$selected = mysql_select_db("p1",$dbh);

$query = mysql_query("SELECT ((MAX(laag_tarief)-MIN(laag_tarief))+(MAX(hoog_tarief)-MIN(hoog_tarief))) as e_totaal, (MAX(laag_tarief)-MIN(laag_tarief)) as e_laag, (MAX(hoog_tarief)-MIN(hoog_tarief)) as e_hoog, (MAX(gas)-MIN(gas)) as g_totaal FROM p1.readings WHERE YEAR(time) = YEAR(CURDATE()) AND MONTH(time) = MONTH(CURDATE())");
$row = mysql_fetch_array($query);
$maandtotaal_e_totaal = $row[0]/1000;
$maandtotaal_e_laag = $row[1]/1000;
$maandtotaal_e_hoog = $row[2]/1000;
$maandtotaal_g = $row[3]/1000;
settype($maandtotaal_e_totaal, "float");
settype($maandtotaal_e_laag, "float");
settype($maandtotaal_e_hoog, "float");
settype($maandtotaal_g, "float");

//Bereken totaal en schrijf weg naar 'dagtotalen' tabel
$SQL = "INSERT INTO p1.maandtotaal (id, time, e_hoog, e_laag, e_totaal, g_totaal) VALUES (NULL, NULL, '".$maandtotaal_e_hoog."', '".$maandtotaal_e_laag."', '".$maandtotaal_e_totaal."', '".$maandtotaal_g."')"; 
//echo $SQL;

//Voer bovenstaande query uit
mysql_query($SQL);

}

?>




Dit bestand haalt de data op voor de staafgrafiek per dag:
data.php
PHP:
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
<?php
$con = mysql_connect("localhost","p1logger","p1logger");

if (!$con) {
  die('Could not connect: ' . mysql_error());
}

mysql_select_db("p1", $con);

$query = mysql_query("SELECT DATE(time) as day, e_hoog, e_laag, e_totaal, verbruik_g FROM dagtotalen ORDER BY day ASC;");

$category = array();
$category['name'] = 'day';

$series1 = array();
$series1['name'] = 'Elektra hoog tarief';

$series2 = array();
$series2['name'] = 'Elektra laag tarief';

$series3 = array();
$series3['name'] = 'Elektra TOTAAL';

$series4 = array();
$series4['name'] = 'Gas';

while($r = mysql_fetch_array($query)) {
    $category['data'][] = $r['day'];
    $series1['data'][] = $r['e_hoog'];
    $series2['data'][] = $r['e_laag'];
    $series3['data'][] = $r['e_totaal'];
    $series4['data'][] = $r['verbruik_g']; 
}

$result = array();
array_push($result,$category);
array_push($result,$series1);
array_push($result,$series2);
array_push($result,$series3);
array_push($result,$series4);

print json_encode($result, JSON_NUMERIC_CHECK);

mysql_close($con);
?>




Dit bestand toont de daadwerkelijke grafiek
index.html
HTML:
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
<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Energieverbruik per dag</title>
        <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script type="text/javascript">
        $(document).ready(function() {
            var options = {
                chart: {
                    renderTo: 'container',
                    type: 'column',
                    marginRight: 130,
                    marginBottom: 25
                },
                title: {
                    text: 'Energieverbruik',
                    x: -20 //center
                },
                subtitle: {
                    text: '',
                    x: -20
                },
                xAxis: {
                    categories: []
                },
                yAxis: {
                    title: {
                        text: 'kWh / m3'
                    },
                    plotLines: [{
                        value: 0,
                        width: 1,
                        color: '#808080'
                    }]
                },
                tooltip: {
                    formatter: function() {
                            return '<b>'+ this.series.name +'</b><br/>'+
                            this.y+ ' kWh / m3';
                    }
                },
                legend: {
                    layout: 'vertical',
                    align: 'right',
                    verticalAlign: 'top',
                    x: -10,
                    y: 100,
                    borderWidth: 0
                },
                series: []
            }
            
            $.getJSON("data.php", function(json) {
                options.xAxis.categories = json[0]['data'];
                options.series[0] = json[1];
                options.series[1] = json[2];
                options.series[2] = json[3];
                options.series[3] = json[4];

                chart = new Highcharts.Chart(options);
            });
        });
        </script>
        <script src="http://code.highcharts.com/highcharts.js"></script>
        <script src="http://code.highcharts.com/modules/exporting.js"></script>
    </head>
    <body>
        <div id="container" style="min-width: 400px; height: 400px; margin: 0 auto"></div>
    </body>
</html>




De code om het gasverbruik te uploaden naar Mindergas vind je hier: ThinkPadd in "Mindergas, upload automatiseren ???"

[ Voor 97% gewijzigd door ThinkPad op 24-09-2014 20:22 ]


Acties:
  • 0 Henk 'm!

  • .SnifraM
  • Registratie: December 2012
  • Niet online
Thinkpad, hoe ziet jou DB table er uit? Wellicht dat je die er ook nog bij kan zetten :-)

lol+lol=hihi


Acties:
  • 0 Henk 'm!

  • ThinkPad
  • Registratie: Juni 2005
  • Laatst online: 17:44
Van die laatste PHP scriptjes met totalen bedoel je? De structuur om m'n meetwaardes op te slaan heb ik beschreven in m'n blogpost namelijk.

dagtotalen
code:
1
2
3
4
5
6
7
8
9
10
11
12
MariaDB [p1]> describe dagtotalen;
+------------+-------------+------+-----+-------------------+----------------+
| Field      | Type        | Null | Key | Default           | Extra          |
+------------+-------------+------+-----+-------------------+----------------+
| id         | int(11)     | NO   | PRI | NULL              | auto_increment |
| time       | timestamp   | NO   |     | CURRENT_TIMESTAMP |                |
| e_hoog     | varchar(11) | NO   |     | NULL              |                |
| e_laag     | varchar(11) | NO   |     | NULL              |                |
| e_totaal   | varchar(11) | NO   |     | NULL              |                |
| verbruik_g | varchar(11) | NO   |     | NULL              |                |
+------------+-------------+------+-----+-------------------+----------------+
6 rows in set (0.03 sec)



maandtotaal
code:
1
2
3
4
5
6
7
8
9
10
11
12
MariaDB [p1]> describe maandtotaal;
+----------+-------------+------+-----+-------------------+----------------+
| Field    | Type        | Null | Key | Default           | Extra          |
+----------+-------------+------+-----+-------------------+----------------+
| id       | int(11)     | NO   | PRI | NULL              | auto_increment |
| time     | timestamp   | NO   |     | CURRENT_TIMESTAMP |                |
| e_hoog   | varchar(11) | NO   |     | NULL              |                |
| e_laag   | varchar(11) | NO   |     | NULL              |                |
| e_totaal | varchar(11) | NO   |     | NULL              |                |
| g_totaal | varchar(11) | NO   |     | NULL              |                |
+----------+-------------+------+-----+-------------------+----------------+
6 rows in set (0.01 sec)


Meeste gewoon nog als varchar, moet eigenlijk naar DECIMAL(5,3) o.i.d., maar dat ging niet helemaal lekker, toen stond er ineens 99.999 in. Ergens met datatype gaat het dus niet helemaal goed in één van m'n scripts. Daarom maar als varchar, dan weet ik iig zeker dat het goed wordt weggeschreven voor nu.

[ Voor 89% gewijzigd door ThinkPad op 26-09-2014 22:55 ]


  • .SnifraM
  • Registratie: December 2012
  • Niet online
Bedankt voor het delen!

Houd er wel rekening mee dat als je in MySQL de MIN, MAX, AVG gaat bepalen aan de hand van een varchar, je hele rare (niet kloppende) getallen krijgt.

Daar liep ik laatst zelf tegenaan : Uitkomst mysql query tegen verwachting (avg, min, max)

lol+lol=hihi

Pagina: 1 2 Laatste