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.
- 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.
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 :-)
if delta.seconds < 10:
and
time.sleep(15)
- 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.
- 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.
- 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.
- 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":
- 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.
- 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":
- 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:
- 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:
#!/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!
@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
<?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.