ENEN DEDE
home
Station available

We wanted to attach a monitor to the wallbox to show the actual power consumption and costs. We also wanted to show the charging status on the website and wanted to be informed by mail on changes of the status.

The charging status is provided by the extra build in digital power meter (see hardware). This device sends 800 impulses per kilowatt hour over its "S0 bus". Now we only need to read that impulse and calculate it into kilowatt hour and Euro. A perfect job for a Raspberry Pi.

A Raspberry Pi ia a small and very cheap mini computer on which a complete Linux operating system can be installed. In our case "Debian Wheezy". You can find all the informtion about the basic configuration of the Raspberry Pi in the net. Here we describe what was needed to modify our wallbox.

  1. The daemon that gets the impulses and processes them:

    The S0 bus is connected to GPIO 2 (+) and GROUND (-) of the Pi (pins 3 and 6).



    Because "Python" is "the" programming language of the Raspberry Pi, the daemon is written in python. The file is called "impsim" and has to be located under "/usr/local/bin/emob/". Note that the file needs to have executable rights.

    Update 20.03.2016

    Due to the super nice cooperation with Benjamin, who implemted the code in his charging station, we found out, that the service runs at 100% processor load. Therefor I did a little rewrite and now we run on 25% processor load. To be complete I linked the old code here.

    Update 21.05.2016

    We found out, that the Leaf needs three little extra charges to level the battery. Within this process the amout of Watts fells under the threshold of the digital power meter. Impsim then thinks the charging is over and sends a mail. 7 times ... Annoying ...

    So I corrected the code. Now a startmail is only send, when the last charging event is a least 330 seconds old and a stopmail is only send, when at least 0.3 kWh have been used.

    This stops the spamming. But it has a disadvantage. When within 5 minutes two different cars start a charging at the station, this is managed as one event. This is not very likely to happen here. Traffic jam at the charging station :-) It could be solved by picking up the "cable connected" signal of the pilot and sent this signal to another GPIO of the Pi. Then impsim could take this signal for charging start / stop. Well, perhaps a future little project ...

    To be complete I linked the code without Leaf correction here.

    The new code starts here:

    /usr/local/bin/emob/impsim:
    #!/usr/bin/env python
    
    import subprocess
    import smtplib
    import socket
    
    from email.mime.text import MIMEText
    
    import time
    import MySQLdb as mdb
    import sys
    
    import RPi.GPIO as GPIO, time, os
    
    from sys import stdout 
    
    from datetime import datetime
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    GPIO.setup(2, GPIO.IN)
    
    gread = 0
    dread = 0
    hcount = 0
    load = 0 
    lch = 0
    imp = 0
    lcheck = 0
    first = 1
    
    now = datetime.now()
    last = now
    lastlast = last
    delta = now - last
    
    pstart = 1
    
    Empf = 'your(at)mail(dot)here'
    Abs = 'your(at)mail(dot)here'
    Passw = 'password'
    smtpserv = smtplib.SMTP_SSL('mailserver_hostname',465)
    smtpserv.ehlo()
    
    # In Account einloggen
    smtpserv.login(Abs, Passw)
    
    Wtxt = 'Ladestation neu gestartet'
    cmsg = MIMEText(Wtxt)
    cmsg['Subject'] = 'Nachricht von der Ladestation'
    
    cmsg['From'] = 'ladestation'
    cmsg['To'] = Empf
    
    smtpserv.sendmail(Abs, [Empf], cmsg.as_string())
    smtpserv.quit()
    
    def RCtime (channel):
    	global first
    	global last
    	global lcheck
    	global gread
    	global dread
    	global hcount
    	global imp
    	imp = 1
    	now = datetime.now()
    	delta = now - last
    	lastlast = last
    	last = now
    	delta = last - lastlast
    	if delta.seconds > 330:
    	    first = 1
    	    hcount = 0
    	    gread = 0
    	    dread = 0
    	if delta.seconds < 40:
    	    if lcheck == 1:
    		first = 0
    		hcount += 1
    		if hcount > 100:
    		    hcount = 1	    
    		gread += 0.00125
    		dread += 0.00125
        		writedb(gread,hcount)
    	    else:
    		setload()
    		lcheck = 1
    		writerem(1)
    		if first == 1:
    		    writedb(gread,hcount)
    		    postit(1, 0)
    		first = 0
    
    def setload ():
        con = None
        try:
            con = mdb.connect('localhost', 'db_user', 'db_pass', 'emob');
            cur = con.cursor()
    	cur.execute("UPDATE emob.settings SET loading='1'")
        	con.commit()
        except mdb.Error, e:
            print "Error %d: %s" % (e.args[0],e.args[1])
            sys.exit(1)
        finally:        
            if con:    
                con.close()
    
    def unsetload ():
        con = None
        try:
            con = mdb.connect('localhost', 'db_user', 'db_pass', 'emob');
            cur = con.cursor()
    	cur.execute("UPDATE emob.settings SET loading='0'")
        	con.commit()
        except mdb.Error, e:
            print "Error %d: %s" % (e.args[0],e.args[1])
            sys.exit(1)
        finally:        
            if con:    
                con.close()
    
    def writedb (akw,fcount):
        loading = 0
        con = None
        try:
            con = mdb.connect('localhost', 'db_user', 'db_pass', 'emob');
            cur = con.cursor()
    	cur.execute("SELECT loading FROM emob.settings")
    	ldata = cur.fetchone()
    	loading = ldata[0]
    	if loading == 1:
    	    cur.execute("SELECT total FROM emob.countings")
    	    data = cur.fetchone()
    	    tkw = data[0]
    	    if fcount == 100:    
    		tkw += 1
    	    sql = "UPDATE emob.countings SET actual=%s, total=%s"
    	    cur.execute(sql, (akw,tkw))
        	con.commit()
        except mdb.Error, e:
            print "Error %d: %s" % (e.args[0],e.args[1])
            sys.exit(1)
        finally:        
            if con:    
                con.close()
        return loading
    
    def writerem (rload):
        con = None
        try:
            con = mdb.connect('remote_host', 'db_user', 'db_pass', 'ips');
            cur = con.cursor()
    	sql = "UPDATE ips.station SET loading=%s"
    	cur.execute(sql, (rload))
        	con.commit()
        except mdb.Error, e:
            print "Error %d: %s" % (e.args[0],e.args[1])
            sys.exit(1)
        finally:        
            if con:    
                con.close()
    
    def postit(pload, pkw):
        Empfaenger = 'your(at)mail(dot)here'
        Absender = 'your(at)mail(dot)here'
        Passwort = 'password'
        smtpserver = smtplib.SMTP_SSL('mailserver_hostname',465)
        smtpserver.ehlo()
    
        # In Account einloggen
        smtpserver.login(Absender, Passwort)
    
        # Text
        if pload == 1:
    	Wert = 'Ladevorgang gestartet'
        if pload == 0:
    	Wert = 'Ladevorgang beendet: %s kWh' % pkw
        msg = MIMEText(Wert)
    
        # Betreff + Datum
        msg['Subject'] = 'Nachricht von der Ladestation'
    
        # Absender
        msg['From'] = 'ladestation'
    
        #Empfaenger
        msg['To'] = Empfaenger
    
        # E-Mail abschicken
        smtpserver.sendmail(Absender, [Empfaenger], msg.as_string())
        smtpserver.quit()
    
    unsetload()
    writedb(0,0)
    
    GPIO.add_event_detect(2, GPIO.RISING, callback = RCtime, bouncetime = 200)
    
    try:
        while True:
    	imp = 0
            time.sleep(60)
    	if imp == 0 and lcheck == 1:
    		unsetload()
    		lcheck = 0
    		writerem(0)
    		if dread > 0.3:
    		    postit(0, gread)
    		dread = 0
    
    except KeyboardInterrupt:
        GPIO.remove_event_detect(2)
    
    There is one little hick up with the new code. The end of the charging process is only recognized after one minute. You can change this by changing the lines


    if delta.seconds < 40:
    and
    time.sleep(60)

    to i.e.

    if delta.seconds < 10:
    and
    time.sleep(15)

    This means that only impulses that come at least every 10 seconds are recogniozied as "charging". 800 impulses per kW, 6 impulses per minute, 360 impulses per hour. So the script triggers only at a usage of about 500 Watt. Good to know on testing :-)
     
  2. The daemon collects the impulses and checks if the occurrence of an impulse is older than 30 seconds. If that is the case, there is no vehicle connected to the wallbox for charging. Do the impuses come in a shorter period than 30 seconds, there is a vehicle connected to the station (this means that there is a charging current of a least about 150 Watt). When the charging starts (or is endet) informations are stored in the local (and in a remote) MySQL database. The local database is called "emob" and needs to be set up. You can download the import-file for the database here. You will also need to create a new user with password and access rights to the emob database. This information also needs to be applied to the source code of impsim in each case of "mdb.connect localhost" as db_name und db_pass.
     
  3. On a (remote) web- and mailserver located in the internet, you also need to have a MySQL database. Here you need to set up the database "ips". The import-file for this database, you can download here. You again need to create a user with password and access rights for this database and enter this information in the impsim source at "mdb.connect remote_hostname". Do also change "remote_hostname" with the fully quallified domainname of your internet server. 
     
  4. To send the mails you need to change "your@mail.here", "password" and the mailserver "mailserver_hostname" in the impsim source code to your needs. The mails are sent using SSL encryption.
     
  5. The impsim daemon needs to started automatically on each system start of the Raspberry Pi. There for you need to edit the file "/etc/rc.local":
     
  6. #!/bin/sh -e
    #
    # rc.local
    #
    # This script is executed at the end of each multiuser runlevel.
    # Make sure that the script will "exit 0" on success or any other
    # value on error.
    #
    # In order to enable or disable this script just change the execution
    # bits.
    #
    # By default this script does nothing.
    
    # Print the IP address
    _IP=$(hostname -I) || true
    if [ "$_IP" ]; then
      printf "My IP address is %s\n" "$_IP"
    fi
    
    /usr/local/bin/emob/impsim &
    exit 0
    

    Update: A tip from Benjamin, who implemented the software at his charging station, is to change "/usr/local/bin/emob/impsim &" to "(/bin/sleep 60 && /usr/local/bin/emob/impsim) &". Thanx!

  7. The display of the power consumption and the costs is done over a website in kiosk mode on the monitor attached to the Pi. There for the apache webserver needs to be installed on the Raspberry Pi. Under the document root (/var/www) you need to unpack this file.In the index.php db_user and db_name have to changed to the needs of the emob database. You can also edit the price per kilowatt hour under "pricing" within the emob database.
     
  8. When the impsim daemon, the database and the webserver are running, we then need to make sure, that the Raspberry Pi will start in graphical mode and starts a webbrowser in kioskmode with our display on show. So first the graphical mode.

    Put the file custom-x-startup.sh under "/etc/init.d".

    Install with "apt-get install midori" the midori browser and edit the file "/etc/xdg/lxsession/LXDE/autostart":
     
  9. @lxpanel --profile LXDE
    @pcmanfm --desktop --profile LXDE
    @xscreensaver -no-splash
    @xset s off
    @xset -dpms
    @xset s noblank
    @midori -e Fullscreen -a http://localhost/index.php
    
  10. Be sure, that you can access your Pi over ssh. After the next reboot you won't have any (easy) direct console anymore! When you checked this you can proceed by entering "sudo update-rc.d custom-x-startup.sh defaults". After reboot the Pi will start in the graphical mode with our display in kiosk mode:



     
  11. The last thing to do, is showing the charging status on the webserver of the remote host, For that put the following code in a php site:
     
  12. <?php
    $loading = 0;
    $link = mysql_connect('localhost', 'db_user', 'db_pass');
    if (!$link) {die('Could not connect: ' . mysql_error());}
    mysql_select_db('ips', $link);
    
    $result = mysql_query("SELECT * FROM station", $link);
    
    if (!$result) {
        die('Invalid query: ' . mysql_error());
    }
    
    while ($row=mysql_fetch_array($result)){
        $loading = $row['loading'];
    }
    
    ?>

    Again change db_user and db_pass to the needs of the ips database.

    The actual display of the charging status is done with this code:

    <?php
    if ($loading == 1) {
        echo '<div style="padding-top:33px; font-face:Arial; font-size:20px;font-weight:bold; color:green;">Station charging</div>';
        } else {
        echo '<div style="padding-top:33px; font-face:Arial; font-size:20px;font-weight:bold; color:green;">Station available</div>';
        }
    ?>

And ready is our "smart little project" :-)

Followup 1:

As teh application is webserverbased and the website on the display refreshes itself every 3 seconds, the log files of the apache webserver overgrow. To prevent this you need to comment out the line "CustomLog ${APACHE_LOG_DIR}/access.log combined" in the file /etc/apache2/sites-available/default with a # to "#CustomLog ${APACHE_LOG_DIR}/access.log combined". After that change the entry Errorlog in the file  /etc/apache2/apache2.conf to "ErrorLog /dev/null" and the log files won't grow any more.

Followup 2:

The pi seems to struggle a bit with the memory consumption of the application. Once in a month the memory overfills. That is where the "oom-killer" jumps in and shuts off the browser. so no displaying any more ... To force the pi into a restart in that case, just enter these two lines to /etc/sysctl.conf:

vm.panic_on_oom = 1
kernel.panic = 5

A quick workaround.

Followup 3:

Benjamin wanted to have a feature, to switch on the monitor, as soon as the charging starts and to switch the monitir off, after some buffer time, when the charging has stopped. He wrote this code for that purpose. To autostart just add a line "/usr/local/bin/emob/screen.py &" (without quotation marks) to the /etc/rc.local file.