Slimme meter uitlezen met Raspberry Pi

Via via kwam ik op zonnestraal.be en hij is bezig met het uitlezen van de slimme meter via de DSMR P1 poort.

Nu Janus (de sitebeheerder van bovenstaande site) kiest ervoor om deze slimme meter om te zetten naar ethernet en vervolgens op een andere computer iets met deze gegevens te doen. (Zijn meet en regel systeem staat op zolder)
Echter, tegenwoordig bestaat er een Raspberry Pi die voor ongeveer 2.5W en een prijs van ongeveer 35 Euro nog een hele hoop extra's kan doen. Dus hier mijn bevindingen.

Historie en uitleg

In septemer 2012 hebben wij een 4410 wp installatie geplaatst van 18 zonnepanelen met een vermoedelijk op te brengen vermogen van (4410*0.85=) 3748 kWh
Dit is allemaal wel leuk en aardig, maar wij willen wel heel graag zien wat wij precies aan stroom maken, terugleveren en weer opmaken.

Per oktober 2012 zijn de regeltjes als volgt. Als particulier mag je tot 5000 kWh terugleveren aan het net, en weer opmaken voor dezelfde prijs. Dus als wij op een goede dag 12 kWh genereren met onze zonnepanelen, hiervan overdag 2 kWh opmaken, en 10 terugleveren aan het net, mogen wij deze, zonder extra kosten, 's avonds weer opmaken. Aangezien de prijs van een kWh op ongeveer 21 cent ligt, (waarvan een 10 cent energiebelasting) kan iedereen wel uitrekenen wat hiervan de kosten en opbrengsten zijn.

Als je bij Enexis aangeeft dat je stroom terug wil leveren, krijg je gratis een slimme meter geplaatst. In mijn geval een Kamstrup 162JxC. Deze meter heeft een DMPR-P1 datapoort. en die laatste, dat is nu net het leuke, dat ding is gewoon een seriele poort. daar kun je dus leuke dingen mee doen.

Kamstrup 162JxC

Kamstrup 162 JxC
Deze meter heeft een data logging poort, ook wel een DSMR P1 poort genoemd. Dit is gewoon een seriele poort, met als uitzondering, dat het signaal geinverteerd is. Ze doen er dus iets lastigs mee, waardoor het niet met een normale seriele kabel uit te lezen is. Zie handleiding meter en handleiding van de datapoort.
Op diverse forums en sites zijn er oplossingen voor gevonden, zoals het herprogrammeren van je seriele kabel (zie post van Maarten), maar ik ben uitermate lui opgezet, dus ik heb een kabel gevonden die het automatisch doet.

Benodigdheden

Raspberry Pi
voeding + kabel voor de Pi
USB to serial cable
db9 connector naar rs11 cable

Raspberry Pi inrichten

Voor we met serieel aan de gang gaan, moet de RPI even ingericht worden. Even wat basale dingen doen. Hierbij ga ik er vanuit dat je zelf al je sd kaart image beschreven hebt, deze hebt geboot en dat je via ipv4 en ssh (of op de console) in kunt loggen.

Eigen user aanmaken

pi@raspberrypi ~ $ sudo useradd -c "Ge Janssen" -d /home/gej -m -s /bin/bash gej
Even wachtwoordje zetten:

pi@raspberrypi ~ $  sudo passwd gej
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
pi@raspberrypi ~ $

Daarna is het handig, als je niet altijd onder root wil werken, de rechten goed te zetten op de seriele poort. De naam van de seriele poort via USB onder linux is /dev/ttyUSB0
Hievoor heeft de groep Dialout voldoende rechten. Dus alle gebruikers die uit moeten lezen, aan de groep dialout toevoegen:

root@raspberrypi:~# ls -l /dev/ttyUSB0
crw-rw---T 1 root dialout 204, 64 Jan  1  1970 /dev/ttyAMA0
root@raspberrypi:~# usermod -a -G dialout gej
root@raspberrypi:~#

gej is mijn gebruiker. Bij andere personen is dat natuurlijk een andere gebruiker, of als je die geen aangemaakt hebt, pi.
Even rechten geven op sudo: (kunnen we eigenlijk ook die wel pi gebruiker in de sudoers file weggooien)

root@raspberrypi:~# vi /etc/sudoers

#includedir /etc/sudoers.d
pi ALL=(ALL) NOPASSWD: ALL
gej ALL=(ALL) NOPASSWD: ALL

Enable IPV6

root@raspberrypi:~# vi /etc/modules

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.

snd-bcm2835
ipv6

Daarna is een reboot handig. Anders doet bijvoorbeeld ssh het niet onder ipv6.

usb to serial

Voor het uitlezen heb je dus een seriele kabel nodig die dat vreemde signaal aankan.
Hiervoor gebruik ik een sitecom usb-serial cable.
Sitecom - USB to serial cable
Deze kabel heeft een straatprijs van ongeveer Euro 15,-
Jarno uit Zoetermeer geeft aan dat deze kabel  in feb 2013 gekocht nog steeds werkt (op zijn Landis meter).
http://tweakers.net/pricewatch/128009/sitecom-cn-104-usb-to-serial-cable-18m.html

Voor de personen die dit te duur vinden, en het geduld hebben om op een bestelling uit China te wachten (levertijd tussen de 10 en de 30 dagen) kun je bij dealextreme het volgende artikelnummer bestellen:
http://dx.com/p/usb-to-rs232-serial-port-adapter-transparent-green-24512?item=4
dx usb to serial
Dit artikel vereist een mega-investering van wel $ 2.99.

Nu, als je eenmaal een seriele kabel hebt wil je deze natuurlijk graag uitlezen om te kijken of alles werkt.
Hiervoor moet je de sub-d 9pins connector even omzetten naar een RJ11 connector. Een beetje solderen is hiervoor vereist, of je moet de volgende kabel kopen voor ongeveer Eur 20,-.
Deze kabel maakt gebruik van de volgende usb-id's (0403:6001) en als je deze op google opzoekt in combinatie met de raspberry pi, krijg je nogal wat hits op crashende Pi's. Voorlopig dus niet kopen totdat de oplossingen opgelost zijn. het lijkt op een hangende usb driver.
Update 10-03-2013 - Frank heeft deze kabel gekocht (Hij had geen zin in dat solderen) en draait al enkele weken stabiel. Misschien is de USB driver geupdate, misschien iets anders. In ieder geval het werkt dus:

Omdat ik geen fan ben van solderen heb ik de gok gewaagd en inmiddels heb ik al enkele weken een stabiele opstelling met de genoemde kabel.

Hier de gegevens van mijn kabel en systeem:

[    3.232337] usb 1-1.2: new full-speed USB device number 4 using dwc_otg
[    3.359185] usb 1-1.2: New USB device found, idVendor=0403, idProduct=6001
[    3.379259] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[    3.399525] usb 1-1.2: Product: P1 Converter Cable
[    3.412230] usb 1-1.2: Manufacturer: FTDI
[    3.418358] usb 1-1.2: SerialNumber: A6WCW7R6
[    6.273805] usb 1-1.2: Detected FT232RL
[    6.279835] usb 1-1.2: Number of endpoints 2
[    6.401525] usb 1-1.2: Endpoint 1 MaxPacketSize 64
[    6.465629] usb 1-1.2: Endpoint 2 MaxPacketSize 64
[    6.517723] usb 1-1.2: Setting MaxPacketSize 64
[    6.559959] usb 1-1.2: FTDI USB Serial Device converter now attached to ttyUSB0

Info uit /proc/version:
Linux version 3.6.11+ (dc4@dc4-arm-01) (gcc version 4.7.2 20120731 (prerelease) (crosstool-NG linaro-1.13.1+bzr2458 - Linaro GCC 2012.08) ) #371 PREEMPT Thu Feb 7 16:31:35 GMT 2013

De slimme meter heeft een 6 pins RJ11 connector, maar pin 1 en 6 hebben we dus niet nodig. We kunnen dus ook een oude telefoondraad met een 4-draads kabel gebruiken.
zie hier het aansluit schema: (NC = not connected)
Met dank aan Maik voor het aangeven dat de RTS verkeerd was.

Ikzelf gebruik die sitecom en die groene van dx.
pin nr
RJ11
signaal sub-D pin nr.
25 pins
sub-D pin nr.
9 pins
2 request (RTS) 4
7
3 ground (GND) 7
5
4 N.C. N.C. N.C.
5 data (RxD) 32
 
en:
RJ11 pinout voor slimme meter DMSR P1 poort

De nummertjes staan op de tekening van de RJ-11 connector en op de Sub-D pins connector.

Mocht hij het "out of the box" niet doen, moet je via die ftdi tools (onder windows) even tegen de usb-serial cable vertellen dat het signaal geinverteerd is. Dit heeft Maarten perfekt beschreven:
http://www.maartendamen.com/2012/04/new-smart-meter-installed-iskra-me382-and-landis-gyr-gasmeter-e06140/

De eerste uitlezing

Nu we de kabel hebben, moeten we hem gaan testen.
Het protocol voor je seriele poort om deze uit te lezen is:

parameter waarde
Baud rate 9600
Data bits 7
Parity Even
Stop bits 1

Hiervoor moeten we even een serieel tooltje installeren. Minicom of nog spartaanser: cu.

pi@raspberrypi ~ $ sudo apt-get install cu minicom
Reading package lists... Done
Building dependency tree      
Reading state information... Done
The following extra packages will be installed:
  lrzsz
The following NEW packages will be installed:
  cu lrzsz minicom
0 upgraded, 3 newly installed, 0 to remove and 5 not upgraded.
Need to get 562 kB of archives.
After this operation, 1,436 kB of additional disk space will be used.
Do you want to continue [Y/n]? y
Get:1 http://mirrordirector.raspbian.org/raspbian/ wheezy/main lrzsz armhf 0.12.21-5 [106 kB]
Get:2 http://mirrordirector.raspbian.org/raspbian/ wheezy/main minicom armhf 2.6.1-1 [314 kB]
Get:3 http://mirrordirector.raspbian.org/raspbian/ wheezy/main cu armhf 1.07-20 [142 kB]
Fetched 562 kB in 0s (699 kB/s)
Selecting previously unselected package lrzsz.
(Reading database ... 57783 files and directories currently installed.)
Unpacking lrzsz (from .../lrzsz_0.12.21-5_armhf.deb) ...
Selecting previously unselected package minicom.
Unpacking minicom (from .../minicom_2.6.1-1_armhf.deb) ...
Selecting previously unselected package cu.
Unpacking cu (from .../archives/cu_1.07-20_armhf.deb) ...
Processing triggers for man-db ...
Processing triggers for menu ...
Setting up lrzsz (0.12.21-5) ...
Setting up minicom (2.6.1-1) ...
Setting up cu (1.07-20) ...
Processing triggers for menu ...
pi@raspberrypi ~ $

Helaas werkt de onboard seriele kaart niet, maar de USB variant wel:

gej@raspberrypi ~ $ cu -l /dev/ttyUSB0 -s 9600 --parity=none
Connected.
/KMP5 KA6U001660297912

0-0:96.1.1(204B413655303031363630323937393132)
1-0:1.8.1(00024.000*kWh)
1-0:1.8.2(00005.000*kWh)
1-0:2.8.1(00026.000*kWh)
1-0:2.8.2(00001.000*kWh)
0-0:96.14.0(0002)
1-0:1.7.0(0000.03*kW)
1-0:2.7.0(0000.00*kW)
0-0:17.0.0(999*A)
0-0:96.3.10(1)
0-0:96.13.1()
0-0:96.13.0()
0-1:24.1.0(3)
0-1:96.1.0(3238313031353431303034303232323131)
0-1:24.3.0(121030140000)(00)(60)(1)(0-1:24.2.1)(m3)
(00024.123)
0-1:24.4.0(1)
!

~. voor exit van het cu pakket.

Voor de betweters, hier een mijn eerste output met een uitleg achter elke regel:
                                                                                                                       
/KMP5 KA6U001660297912                                                          serienummer meter                                
                                                                                                                       
0-0:96.1.1(204B413655303031363630323937393132)                                                                         
1-0:1.8.1(00013.000*kWh)                                                        +T1 = 13     Afgenomen stroom daltarief 13 kWh
8.2(00001.000*kWh)                                                              +T2 = 1      Afgenomen stroom piektarief 1 kWh     
1-0:2.8.1(00026.000*kWh)                                                        -T1 = 26     Teruggeleverde stroom daltarief 26 kWh
1-0:2.8.2(00000.000*kWh)                                                        -T2 = 0      Teruggeleverde stroom piektarief 0 kWh
0-0:96.14.0(0001)                                                               Aktuele tarief (1) dus daltief
1-0:1.7.0(0000.54*kW)                                                           Huidig verbruik (afgenomen vermogen) 540 Watt
1-0:2.7.0(0000.00*kW)                                                           Huidige teruglevering 0 Watt
0-0:17.0.0(999*A)                                                               Maximum stroom/fase
0-0:96.3.10(1)                                                                  stand van de schakelaar
0-0:96.13.1()                                                                   bericht numeriek
0-0:96.13.0()                                                                   bericht tekst
0-1:24.1.0(3)                                                                   andere apparaten op de M-Bus
0-1:96.1.0(3238313031353431303034303232323131)                                  identificatie van de gasmeter
0-1:24.3.0(121028200000)(00)(60)(1)(0-1:24.2.1)(m3)                             tijd van de laatste gasmeting (121028200000) 2012-10-28
(00015.475)                                                                     verbruikte hoeveelheid 15 m3 gas
0-1:24.4.0(1)                                                                   stand gasklep
!                                                                               afsluiter\

Python pyserial installeren

Voor het uitlezen via python moet je even pyserial installeren.

root@raspberrypi:~# easy_install -U pyserial
Searching for pyserial
Reading http://pypi.python.org/simple/pyserial/
Reading http://pyserial.sourceforge.net/
Best match: pyserial 2.6
Downloading http://pypi.python.org/packages/source/p/pyserial/pyserial-2.6.tar.gz#md5=cde799970b7c1ce1f7d6e9ceebe64c98
Processing pyserial-2.6.tar.gz
Running pyserial-2.6/setup.py -q bdist_egg --dist-dir /tmp/easy_install-FDqSou/pyserial-2.6/egg-dist-tmp-q55WJR
warning: no files found matching 'examples/miniterm.py'
warning: no files found matching 'test/test_io_lib.py'
zip_safe flag not set; analyzing archive contents...
Adding pyserial 2.6 to easy-install.pth file
Installing miniterm.py script to /usr/local/bin

Installed /usr/local/lib/python2.7/dist-packages/pyserial-2.6-py2.7.egg
Processing dependencies for pyserial
Finished processing dependencies for pyserial
root@raspberrypi:~#

Python script voor het uitlezen van de seriele poort

De output van de slimme meter is precies 20 regels lang. Dus even een scriptje in elkaar zetten die die 20 regels uitleest.

gej@raspberrypi ~ $ vi P1uitlezen.py
# DSMR P1 uitlezen
# (c) 10-2012 - GJ - gratis te kopieren en te plakken
versie = "1.0"
import sys
import serial

##############################################################################
#Main program
##############################################################################
print ("DSMR P1 uitlezen",  versie)
print ("Control-C om te stoppen")
print ("Pas eventueel de waarde ser.port aan in het python script")

#Set COM port config
ser = serial.Serial()
ser.baudrate = 9600
ser.bytesize=serial.SEVENBITS
ser.parity=serial.PARITY_EVEN
ser.stopbits=serial.STOPBITS_ONE
ser.xonxoff=0
ser.rtscts=0
ser.timeout=20
ser.port="/dev/ttyUSB0"

#Open COM port
try:
    ser.open()
except:
    sys.exit ("Fout bij het openen van %s. Aaaaarch."  % ser.name)


#Initialize
#p1_teller is mijn tellertje voor van 0 tot 20 te tellen
p1_teller=0

while p1_teller < 20:
    p1_line=''
#Read 1 line van de seriele poort
    try:
        p1_raw = ser.readline()
    except:
        sys.exit ("Seriele poort %s kan niet gelezen worden. Aaaaaaaaarch." % ser.name )
    p1_str=str(p1_raw)
    p1_line=p1_str.strip()
# als je alles wil zien moet je de volgende line uncommenten
    print (p1_line)
    p1_teller = p1_teller +1

#Close port and show status
try:
    ser.close()
except:
    sys.exit ("Oops %s. Programma afgebroken. Kon de seriele poort niet sluiten." % ser.name )

Je kunt hem natuurlijk ook hier downloaden: Python P1uitlezen.py script

En dan het script voor de eerste keer uitvoeren.

gej@raspberrypi ~ $ python P1uitlezen.py
('DSMR P1 uitlezen', '1.0')
Control-C om te stoppen
Pas eventueel de waarde ser.port aan in het python script
/KMP5 KA6U001660297912

0-0:96.1.1(204B413655303031363630323937393132)
1-0:1.8.1(00068.000*kWh)
1-0:1.8.2(00024.000*kWh)
1-0:2.8.1(00027.000*kWh)
1-0:2.8.2(00028.000*kWh)
0-0:96.14.0(0002)
1-0:1.7.0(0000.00*kW)
1-0:2.7.0(0000.12*kW)
0-0:17.0.0(999*A)
0-0:96.3.10(1)
0-0:96.13.1()
0-0:96.13.0()
0-1:24.1.0(3)
0-1:96.1.0(3238313031353431303034303232323131)
0-1:24.3.0(121106150000)(00)(60)(1)(0-1:24.2.1)(m3)
(00054.386)
0-1:24.4.0(1)
!

Aanpassingen python script

Omdat er meer slimme meters zijn dan mijn Kamstrup en sommige net wat anders doen als ik verwacht, hier een paar aanpassingen:

Landis gyr E350 zonder gasmeter:
Even tellen:

1    /XMX5XMXABCE000059909
2
3    0-0:96.1.1(31333630359995332020302020202020)
4    1-0:1.8.1(00007.310*kWh)
5    1-0:1.8.2(00009.848*kWh)
6    1-0:2.8.1(00000.000*kWh)
7    1-0:2.8.2(00000.000*kWh)
8    0-0:96.14.0(0001)
9    1-0:1.7.0(0000.27*kW)
10    1-0:2.7.0(0000.00*kW)
11    0-0:17.0.0(999*A)
12    0-0:96.3.10(1)
13    0-0:96.13.1()
14    0-0:96.13.0()
15    !

Dus 15 regels in plaats van de 20 die ik heb, even de counter in hett python script aanpassen:

volgende regel opzoeken en aanpassen
#Initialize
#p1_teller is mijn tellertje voor van 0 tot 20 te tellen
p1_teller=0

while p1_teller < 20:
    p1_line=''

van de 20 even 15 maken.

P1uitlezer.py naar Kwh en m3 in plaats van W en dm3

Zoek in het P1uitlezer.py script de volgene regels op.
while stack_teller < 20:
if stack[stack_teller][0:9] == "1-0:1.8.1":
print "daldag ", stack[stack_teller][10:15]
elif stack[stack_teller][0:9] == "1-0:1.8.2":
print "piekdag ", stack[stack_teller][10:15]
# Daltarief, teruggeleverd vermogen 1-0:2.8.1
elif stack[stack_teller][0:9] == "1-0:2.8.1":
print "dalterug ", stack[stack_teller][10:15]
# Piek tarief, teruggeleverd vermogen 1-0:2.8.2
elif stack[stack_teller][0:9] == "1-0:2.8.2":
print "piekterug ", stack[stack_teller][10:15]
# Huidige stroomafname: 1-0:1.7.0
elif stack[stack_teller][0:9] == "1-0:1.7.0":
print "afgenomen vermogen ", int(float(stack[stack_teller][10:17])*1000), " W"
# Huidig teruggeleverd vermogen: 1-0:1.7.0
elif stack[stack_teller][0:9] == "1-0:2.7.0":
print "teruggeleverd vermogen ", int(float(stack[stack_teller][10:17])*1000), " W"
# Gasmeter: 0-1:24.3.0
elif stack[stack_teller][0:10] == "0-1:24.3.0":
print "Gas ", int(float(stack[stack_teller+1][1:10])*1000), " dm3"
else:
pass
stack_teller = stack_teller +1

Wat ik eigenlijk doe is de waarde die ik uitlees, omzetten naar een float en daarna naar een integer, om er vervolgens mee te kunnen rekenen. Als je dit niet wil, is het makkelijkste die *1000 weg te halen en dan heb je de originele getallen weer met cijfertjes achter de .
Hiermee kan mijn mrtg en mijn rrd niet omgaan, vandaar die omrekening. De waarde zelf mag je dan op eigen initiatief aanpassen :-)

Apache installatie

Als we deze info willen gaan misbruiken, is mijn makkelijkste interface altijd een browser. Dus even apache installeren.

gej@raspberrypi ~ $ sudo apt-get install apache2
Reading package lists... Done
Building dependency tree      
Reading state information... Done
The following extra packages will be installed:
  apache2-mpm-worker apache2-utils apache2.2-bin apache2.2-common libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap ssl-cert
Suggested packages:
  apache2-doc apache2-suexec apache2-suexec-custom openssl-blacklist
The following NEW packages will be installed:
  apache2 apache2-mpm-worker apache2-utils apache2.2-bin apache2.2-common libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap ssl-cert
0 upgraded, 10 newly installed, 0 to remove and 5 not upgraded.
Need to get 1,348 kB of archives.
After this operation, 4,990 kB of additional disk space will be used.
Do you want to continue [Y/n]? y
...
Setting up apache2-mpm-worker (2.2.22-11) ...
[....] Starting web server: apache2apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName. ok
Setting up apache2 (2.2.22-11) ...
Setting up ssl-cert (1.0.32) ...
gej@raspberrypi ~ $

Via internet heb ik wat interessante pagina's uitgevonden om shell commando's uit te voeren vanuit een browser sessie.
http://www.ibm.com/developerworks/opensource/library/os-php-commandline/index.html
commands in php scripts

Hiervoor hebben we php nodig.

PHP installeren

gej@raspberrypi /var/www $ sudo apt-get install php5
Reading package lists... Done
Building dependency tree      
Reading state information... Done
The following extra packages will be installed:
  apache2-mpm-prefork libapache2-mod-php5 libonig2 libqdbm14 php5-cli php5-common
Suggested packages:
  php-pear
The following packages will be REMOVED:
  apache2-mpm-worker
The following NEW packages will be installed:
  apache2-mpm-prefork libapache2-mod-php5 libonig2 libqdbm14 php5 php5-cli php5-common
0 upgraded, 7 newly installed, 1 to remove and 5 not upgraded.
Need to get 5,707 kB of archives.
After this operation, 16.3 MB of additional disk space will be used.
Do you want to continue [Y/n]? y
...
Creating config file /etc/php5/apache2/php.ini with new version
[....] Restarting web server: apache2apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
 ... waiting apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName . ok
Setting up php5 (5.4.4-7) ...
Setting up php5-cli (5.4.4-7) ...
Creating config file /etc/php5/cli/php.ini with new version
update-alternatives: using /usr/bin/php5 to provide /usr/bin/php (php) in auto mode
gej@raspberrypi /var/www $

gej@raspberrypi /var/www $ sudo service apache2 restart
[....] Restarting web server: apache2apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
 ... waiting apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
. ok
gej@raspberrypi /var/www $

effe www-data toevoegen aan de groep dialout (rechten op de compoort) zodat het scriptje dadelijk kan draaien vanuit de browser.

root@raspberrypi:~# usermod -a -G dialout www-data
root@raspberrypi:~#

PHP script voor uitvoer shell command

gej@raspberrypi ~ $ sudo vi /var/www/readserial.php
<html>
  <body>
    <pre>
<?php
#$command=system("/usr/bin/python /home/gej/P1uitlezen.py");
#$command=system("/usr/bin/python /home/gej/P1uitlezer.py 2>&1");
$command=system("/usr/bin/python /home/gej/P1uitlezer.py");

?>
    </pre>
  </body>
</html>

Ook deze kun je weer hier downloaden (denk er wel aan, rechtermuistoets, save as): readserial.php net als P1uitlezer.py script. Deze past nog ietwat formatering toe.

Daarna kun je via de browser naar de raspberrypi gaan en dan naar de pagina /readserial.php

screenshot van een php script om de slimme meter uit te lezen

Als je de output niet leuk vind, kun je teruggaan naar de originele output door het pythonscript P1uitlezen.py aan te roepen.
Mocht je tegen problemen aanlopen, is een reboot van de pi wel eens handig, of in het ergste geval de regel met 2>&1 uitcommenten. Dan krijg je de foutmeldingen (zoals het niet kunnen openen van je seriele poort) te zien in je browser.
als je veel fouten hebt gemaakt, blijft er wel eens een python script hangen. Dus even alle python commando's die nog lopen afschieten.


gej@raspberrypi ~ $ ps -ef | grep python
gej       4113  3836  0 15:14 pts/0    00:00:00 grep --color=auto python

Niets aan de hand....

Maar hier wel:

gej@raspberrypi ~ $ ps -ef | grep python
www-data  4114 14182  0 15:14 ?        00:00:00 sh -c /usr/bin/python /home/gej/P1uitlezer.py
www-data  4115  4114 29 15:14 ?        00:00:00 /usr/bin/python /home/gej/P1uitlezer.py
gej       4117  3836  0 15:14 pts/0    00:00:00 grep --color=auto python
gej@raspberrypi ~ $ kill 4114 4115

Huidige status

Nu ik zo'n beetje weet hoe ik aan de data moet komen, ben ik aan het experimenteren wat er mee te doen.
Grafiekjes spreken het meest, dus hierbij een paar voorbeelden.
Mocht je geinteresseert zijn in de setup, geef maar een mailtje of zoiets, dan zet ik het er even bij.
Overigens, de pi is nu bezig met uitlezen elke 5 minuten, data bijvullen in de rrd databases, apache draaien voor mezelf en die mrtg site en nog steeds is hij niet druk bezig:
raspberry pi - cpu power

MRTG

uitlezen slimme meter met MRTG
http://ftth.gejanssen.com/slimmemeter/localhost_meter.html
Voor de duidelijkheid. Groen is wat we afnemen van het net in Watt per uur, en die blauwe lijn is wat we terugleveren aan het net.
Nadeel, mrtg kan niet overweg met negatieve waardes, en het terugleveren zag ik graag negatief op de grafiek. Dus door naar rrd.

gebruikte power.conf

# Created by
# /usr/bin/cfgmaker power


### Global Config Options
#  for UNIX
# WorkDir: /home/http/mrtg
WorkDir: /var/www/html/slimmemeter

#  or for NT
# WorkDir: c:\mrtgdata

### Global Defaults

#  to get bits instead of bytes and graphs growing to the right
# Options[_]: growright, bits

EnableIPv6: no
# polling interval 5 minute
Interval: 5
# refresh html every 300 seconds
Refresh: 300

######################################################################
# System: linux
# Description: Slimme meter
# Contact: Sysadmin (root@localhost)
# Location: Server Room
######################################################################
Options[localhost_meter]: growright,integer,gauge,nopercent
Target[localhost_meter]: `/bin/grep afgenomen slimmemeter.txt | /bin/awk '{print $3}'; /bin/grep teruggeleverd slimmemeter.txt | /bin/awk '{print $3}'`
Ylegend[localhost_meter]: W
Shortlegend[localhost_meter]: W
legend1[localhost_meter]: W
LegendI[localhost_meter]: Watt afgenomen
LegendO[localhost_meter]: Watt geleverd
Withpeak[localhost_meter]: ymwd
MaxBytes[localhost_meter]: 4000
Title[localhost_meter]: Input output power -- slimme meter
PageTop[localhost_meter]: <h1>Powerin- and output -- slimme meter</h1>
                <div id="sysdetails">
                        <table>
                                <tr>
                                        <td>Slimme meter:</td>
                                        <td>In de meterkast</td>
                                </tr>
                                <tr>
                                        <td>Watt in</td>
                                        <td>Watt out</td>
                                </tr>
                                <tr>
                                        <td>Max Watt:</td>
                                        <td>4000</td>
                                </tr>
                        </table>
                </div>

en dan met indexmaker even de default pagina generen in /var/www/html/slimmemeter

en dan via de crontab mrtg draaien via het volgende commando

env LANG=C /usr/bin/mrtg power.cfg

rrdpower

rrd power daily
de volgende stappen zijn nodig om rrdpower te maken:
elke 5 minuten een p1uitlezer.py wegschrijven naar een bestandje
uit dit bestandje de powerin en de powerout uit destileren
dit als twee verschillende waardes in rrd wegschrijven.

Dit bleek voor de meeste lezers meer moeite dan ik dacht, dit heb ik verder uitgewerkt op de volgende pagina:

http://gejanssen.com/howto/rpi-rrd-power/index.html

rrd gas

uitlezen slimme gas meter met rrd
Ben nog een beetje aan het spelen met de waardes. Momenteel haal ik elke 5 minuten de data op, en het verschil tussen nu en de vorige keer, laat ik nu zien.
Wil nog iets gaan doen met een dagelijks overzicht wat ik afgenomen heb die dag.
http://raspberrypi.gejanssen.com/rrdgas/gas.php (werkt alleen als je ipv6 netwerk hebt) 

rrd temperatuur

uitlezen temperatuur met rrd
Experimentje met de interne temperatuur van de sensor. Binnenkort komt mijn DHT11 temperatuur sensor en mijn DS18B20 sensor. Allebei zonder veel moeite aan te sluiten op de gpio poort van de raspberry.
http://raspberrypi.gejanssen.com/rrdtemp/temperature.php (ipv6 only)

Mysql database

Voor het vullen van mijn mysql database ben ik nog op zoek naar een mooi datamodel.

Installeren mysql-server

Tijdens installeren moet je een wachtwoord ingeven
Database123

gej@raspberrypi:~# sudo apt-get install mysql-server
Reading package lists... Done
Building dependency tree      
Reading state information... Done
The following extra packages will be installed:
  heirloom-mailx libaio1 libdbd-mysql-perl libdbi-perl libhtml-template-perl libmysqlclient16 libnet-daemon-perl
  libplrpc-perl mysql-client-5.5 mysql-common mysql-server-5.5 mysql-server-core-5.5
Suggested packages:
  exim4 mail-transport-agent libipc-sharedcache-perl libterm-readkey-perl tinyca
Recommended packages:
  mailx
The following NEW packages will be installed:
  heirloom-mailx libaio1 libdbd-mysql-perl libdbi-perl libhtml-template-perl libmysqlclient16 libnet-daemon-perl
  libplrpc-perl mysql-client-5.5 mysql-common mysql-server mysql-server-5.5 mysql-server-core-5.5
0 upgraded, 13 newly installed, 0 to remove and 3 not upgraded.
Need to get 9950 kB of archives.
After this operation, 91.1 MB of additional disk space will be used.
Do you want to continue [Y/n]? y
Get:1 http://mirrordirector.raspbian.org/raspbian/ wheezy/main libaio1 armhf 0.3.109-3 [8944 B]
Get:2 http://mirrordirector.raspbian.org/raspbian/ wheezy/main mysql-common all 5.5.28+dfsg-1 [89.1 kB]
Get:3 http://mirrordirector.raspbian.org/raspbian/ wheezy/main libnet-daemon-perl all 0.48-1 [46.2 kB]
Get:4 http://mirrordirector.raspbian.org/raspbian/ wheezy/main libplrpc-perl all 0.2020-2 [36.0 kB]
Get:5 http://mirrordirector.raspbian.org/raspbian/ wheezy/main libdbi-perl armhf 1.622-1 [895 kB]
Get:6 http://mirrordirector.raspbian.org/raspbian/ wheezy/main libmysqlclient16 armhf 5.1.62-1 [1828 kB]
Get:7 http://mirrordirector.raspbian.org/raspbian/ wheezy/main libdbd-mysql-perl armhf 4.021-1 [123 kB]
Get:8 http://mirrordirector.raspbian.org/raspbian/ wheezy/main mysql-client-5.5 armhf 5.5.28+dfsg-1 [1552 kB]
Get:9 http://mirrordirector.raspbian.org/raspbian/ wheezy/main mysql-server-core-5.5 armhf 5.5.28+dfsg-1 [3341 kB]
Get:10 http://mirrordirector.raspbian.org/raspbian/ wheezy/main mysql-server-5.5 armhf 5.5.28+dfsg-1 [1619 kB]        
Get:11 http://mirrordirector.raspbian.org/raspbian/ wheezy/main heirloom-mailx armhf 12.5-2 [253 kB]                  
Get:12 http://mirrordirector.raspbian.org/raspbian/ wheezy/main libhtml-template-perl all 2.91-1 [72.0 kB]            
Get:13 http://mirrordirector.raspbian.org/raspbian/ wheezy/main mysql-server all 5.5.28+dfsg-1 [87.3 kB]              
Fetched 9950 kB in 9s (1081 kB/s)                                                                                     
perl: warning: Setting locale failed.
Preconfiguring packages ...
Selecting previously unselected package libaio1:armhf.
(Reading database ... 65715 files and directories currently installed.)
Unpacking libaio1:armhf (from .../libaio1_0.3.109-3_armhf.deb) ...
Selecting previously unselected package mysql-common.
Unpacking mysql-common (from .../mysql-common_5.5.28+dfsg-1_all.deb) ...
Selecting previously unselected package libnet-daemon-perl.
Unpacking libnet-daemon-perl (from .../libnet-daemon-perl_0.48-1_all.deb) ...
Selecting previously unselected package libplrpc-perl.
Unpacking libplrpc-perl (from .../libplrpc-perl_0.2020-2_all.deb) ...
Selecting previously unselected package libdbi-perl.
Unpacking libdbi-perl (from .../libdbi-perl_1.622-1_armhf.deb) ...
Selecting previously unselected package libmysqlclient16.
Unpacking libmysqlclient16 (from .../libmysqlclient16_5.1.62-1_armhf.deb) ...
Selecting previously unselected package libdbd-mysql-perl.
Unpacking libdbd-mysql-perl (from .../libdbd-mysql-perl_4.021-1_armhf.deb) ...
Selecting previously unselected package mysql-client-5.5.
Unpacking mysql-client-5.5 (from .../mysql-client-5.5_5.5.28+dfsg-1_armhf.deb) ...
Selecting previously unselected package mysql-server-core-5.5.
Unpacking mysql-server-core-5.5 (from .../mysql-server-core-5.5_5.5.28+dfsg-1_armhf.deb) ...
Processing triggers for man-db ...
Setting up mysql-common (5.5.28+dfsg-1) ...
Selecting previously unselected package mysql-server-5.5.
(Reading database ... 66096 files and directories currently installed.)
Unpacking mysql-server-5.5 (from .../mysql-server-5.5_5.5.28+dfsg-1_armhf.deb) ...
Selecting previously unselected package heirloom-mailx.
Unpacking heirloom-mailx (from .../heirloom-mailx_12.5-2_armhf.deb) ...
Selecting previously unselected package libhtml-template-perl.
Unpacking libhtml-template-perl (from .../libhtml-template-perl_2.91-1_all.deb) ...
Selecting previously unselected package mysql-server.
Unpacking mysql-server (from .../mysql-server_5.5.28+dfsg-1_all.deb) ...
Processing triggers for man-db ...
Processing triggers for menu ...
Setting up libaio1:armhf (0.3.109-3) ...
Setting up libnet-daemon-perl (0.48-1) ...
Setting up libplrpc-perl (0.2020-2) ...
Setting up libdbi-perl (1.622-1) ...
Setting up libmysqlclient16 (5.1.62-1) ...
Setting up libdbd-mysql-perl (4.021-1) ...
Setting up mysql-client-5.5 (5.5.28+dfsg-1) ...
Setting up mysql-server-core-5.5 (5.5.28+dfsg-1) ...
Setting up mysql-server-5.5 (5.5.28+dfsg-1) ...
[ ok ] Stopping MySQL database server: mysqld.
130203 22:04:18 [Note] Plugin 'FEDERATED' is disabled.
130203 22:04:18 InnoDB: The InnoDB memory heap is disabled
130203 22:04:18 InnoDB: Mutexes and rw_locks use GCC atomic builtins
130203 22:04:18 InnoDB: Compressed tables use zlib 1.2.7
130203 22:04:18 InnoDB: Using Linux native AIO
130203 22:04:19 InnoDB: Initializing buffer pool, size = 128.0M
130203 22:04:19 InnoDB: Completed initialization of buffer pool
130203 22:04:19 InnoDB: highest supported file format is Barracuda.
130203 22:04:19  InnoDB: Waiting for the background threads to start
130203 22:04:20 InnoDB: 1.1.8 started; log sequence number 1595675
130203 22:04:20  InnoDB: Starting shutdown...
130203 22:04:23  InnoDB: Shutdown completed; log sequence number 1595675
[ ok ] Starting MySQL database server: mysqld . . ..
[info] Checking for tables which need an upgrade, are corrupt or were
not closed cleanly..
Setting up heirloom-mailx (12.5-2) ...
update-alternatives: using /usr/bin/heirloom-mailx to provide /usr/bin/mailx (mailx) in auto mode
Setting up libhtml-template-perl (2.91-1) ...
Setting up mysql-server (5.5.28+dfsg-1) ...
Processing triggers for menu ...
root@raspberrypi:~#

Aanmaken database

Even kijken welke databases we hebben

root@raspberrypi:~# mysqlshow -u root -p
Enter password:
+--------------------+
|     Databases      |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
root@raspberrypi:~# df
Filesystem     1K-blocks    Used Available Use% Mounted on
rootfs           3818192 1834380   1789944  51% /
/dev/root        3818192 1834380   1789944  51% /
devtmpfs           94488       0     94488   0% /dev
tmpfs              18912     220     18692   2% /run
tmpfs               5120       0      5120   0% /run/lock
tmpfs              37820       0     37820   0% /run/shm
/dev/mmcblk0p1     57288   16872     40416  30% /boot
root@raspberrypi:~#

Nieuwe database aanmaken

naam van de database wordt: p1db

root@raspberrypi:~# mysql -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 43
Server version: 5.5.28-1 (Debian)

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database p1db;
Query OK, 1 row affected (0.01 sec)

mysql> exit
Bye
root@raspberrypi:~#

En dan controleren of de nieuwe database er is.

root@raspberrypi:~# mysqlshow -u root -p
Enter password:
+--------------------+
|     Databases      |
+--------------------+
| information_schema |
| mysql              |
| p1db               |
| performance_schema |
| test               |
+--------------------+
root@raspberrypi:~#

of

gej@raspberrypi(gej): ~ $ mysql -p --user=root
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 46
Server version: 5.5.28-1 (Debian)

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| p1db               |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.01 sec)

mysql>


Tabellen aanmaken

gej@raspberrypi(gej): ~ $ mysql --user=root --password=Database123 p1db < create_table_p1db.sql
gej@raspberrypi(gej): ~ $


Kijken of het gelukt is:

gej@raspberrypi(gej): ~ $ mysql --user=root --password=Database123 p1db                        
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 48
Server version: 5.5.28-1 (Debian)

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show tables;
+----------------+
| Tables_in_p1db |
+----------------+
| P1uitlezen     |
+----------------+
1 row in set (0.00 sec)

mysql> desc P1uitlezen;
+-----------------------+--------------+------+-----+---------+-------+
| Field                 | Type         | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------+-------+
| DateTime              | varchar(255) | NO   | PRI | NULL    |       |
| date                  | int(11)      | NO   |     | NULL    |       |
| time                  | varchar(5)   | NO   |     | NULL    |       |
| T1afgenomen           | int(11)      | NO   |     | NULL    |       |
| T2afgenomen           | int(11)      | NO   |     | NULL    |       |
| T1terug               | int(11)      | NO   |     | NULL    |       |
| T2terug               | int(11)      | NO   |     | NULL    |       |
| Tarief                | int(11)      | NO   |     | NULL    |       |
| Afgenomenvermogen     | int(11)      | NO   |     | NULL    |       |
| Teruggeleverdvermogen | int(11)      | NO   |     | NULL    |       |
| Temperature           | decimal(3,1) | NO   |     | NULL    |       |
+-----------------------+--------------+------+-----+---------+-------+
11 rows in set (0.02 sec)

mysql>









#Server Connection to MySQL:

import MySQLdb
conn
= MySQLdb.connect(host= "localhost",
user="root",
passwd
="newpassword",
db
="engy1")
x
= conn.cursor()

try
:
x
.execute("""INSERT INTO anooog1 VALUES (%s,%s)""",(188,90))
conn
.commit()
except:
conn
.rollback()

conn
.close()

edit working for me:

>>> import MySQLdb
>>> #connect to db
... db = MySQLdb.connect("localhost","root","password","testdb" )
>>>
>>> #setup cursor
... cursor = db.cursor()
>>>
>>> #create anooog1 table
... cursor.execute("DROP TABLE IF EXISTS anooog1")
__main__
:2: Warning: Unknown table 'anooog1'
0L
>>>
>>> sql = """CREATE TABLE anooog1 (
... COL1 INT,
... COL2 INT )"""

>>> cursor.execute(sql)
0L
>>>
>>> #insert to table
... try:
... cursor.execute("""INSERT INTO anooog1 VALUES (%s,%s)""",(188,90))
... db.commit()
... except:
... db.rollback()
...
1L
>>> #show table
... cursor.execute("""SELECT * FROM anooog1;""")
1L
>>> print cursor.fetchall()
((188L, 90L),)
>>>
>>> db.close()

table in mysql;

mysql> use testdb;
Reading
table information for completion of table and column names
You can turn
off this feature to get a quicker startup with -A

Database changed
mysql
> SELECT * FROM anooog1;
+------+------+
| COL1 | COL2 |
+------+------+
| 188 | 90 |
+------+------+
1 row in set (0.00 sec)

mysql
>





http://zetcode.com/db/mysqlpython/

#!/usr/bin/python
# -*- coding: utf-8 -*-

import _mysql
import sys


con = None

try:

con = _mysql.connect('localhost', 'testuser',
'test623', 'testdb')

con.query("SELECT VERSION()")
result = con.use_result()

print "MySQL version: %s" % \
result.fetch_row()[0]

except _mysql.Error, e:

print "Error %d: %s" % (e.args[0], e.args[1])
sys.exit(1)

finally:

if con:


con.close()
Create a new database:
mysql> create database test;

Create a new user with local privileges:
mysql> create user 'pi'@'localhost' identified by 'raspberry';

Allow full access to the 'test' database:
mysql> grant all privileges on test.* to 'pi'@'localhost';

Clean up:
mysql> flush privileges;
mysql> quit;

Now to create a PHP script to test the connection to the test database using the new user:
# cd /var/www
# nano testmysql.php
<%php
//Try connection
$db=mysqli_connect('localhost', 'pi', 'raspberry', 'test') or die ("Failed to connect: " . mysqli_error());
echo "Connected OK.";
// Clean up
mysqli_close($db);
?>
Results in the exciting output:

Todo

Data naar database of csv file
data uitlezen grafiekje maken: http://ictoblog.nl/raspberry-pi/daily-sma-bluetooth-report-via-e-mail-version-2