Ladebox für Elektroautos
Verfasst: 12.06.2016 - 16:38
Wir haben uns vor kurzem ein Elektroauto angeschafft für das ich eine Tankstelle gebaut habe.
Zu finden ist diese hier und hier.
Die Ladebox kann 43kW über ein festes Typ2 Kabel liefern oder 22kW über eine CEE32 Dose.
Nutzbar ist die Ladebox für jeden ohne vorherige Anmeldung. Eine Spende in Höhe des verbrauchten Stromes wäre aber nett.
Eigentlich ist dort alles "Standard". Nur die Ladesteuerung wird von einer simpleEVSE übernommen.
Die Visualisierung übernimmt dabei ein Raspi.
Als ich damit anfing bin ich auf das Projekt von Chris gestoßen und habe das gleich mal getestet und benutze das jetzt.
Leider ist schnell aufgefallen dass der Pi dauerhaft bei nahezu 100% Auslastung verweilt.
Nachdem ich mich aber etwas damit beschäftigte war die Ursache dafür schnell gefunden.
Die GPIOs wurden "aktiv" überwacht. Nachdem ich ein Testscript gebastelt hatte, dass die Impulse per Interrupt abfängt hat Chris seinen impsim.py dem angepasst. Seid dem läuft der Raspi unter 10%.
Ich hänge mal einige Bilder an und auch die Quellcodes für den Raspi.
Der Schaltplan (K5 ist bei mir noch überbrückt, da nicht konfiguriert) Die Unterverteilung UV_Keller: Die Ladebox im bau (Der Zähler ist in die UV_Keller gezogen) Die Befestigung der simpleEVSE Die fertige Ladebox
Die config.txt vom Raspi:
Der S0-Bus des Zählers wird an GPIO 2 (+) und GROUND (-) des Pi angeschlossen (Pins 3 und 6).
Die /usr/local/bin/emob/impsim.py zählt die Impulse
Die /usr/local/bin/emob/screen.py schaltet den Monitor ein und mit Verzögerung nach dem Ladevorgang wieder aus.
Die Importdatei emobsql.sql für den lokalen MySQL-Server
Die Importdatei ips.sql für die remote MySQL-Datenbank z.B. beim Provider:
(Diese musste ich z.B. anpassen, da mein Provider den DB-Namen vorgibt.)
Die /home/pi/startMidori.sh Datei für den Windowmanager (hier matchbox) und den Browserstart.
Die /etc/rc.local zum steuern des Autostart
Hier die der Code, der in die externe Webseite gehört:
...und hier die eigentliche Anzeige:
Die lokale Webseite.
Nochmal der Verweis auf Chris Projekt.
Zu finden ist diese hier und hier.
Die Ladebox kann 43kW über ein festes Typ2 Kabel liefern oder 22kW über eine CEE32 Dose.
Nutzbar ist die Ladebox für jeden ohne vorherige Anmeldung. Eine Spende in Höhe des verbrauchten Stromes wäre aber nett.
Eigentlich ist dort alles "Standard". Nur die Ladesteuerung wird von einer simpleEVSE übernommen.
Die Visualisierung übernimmt dabei ein Raspi.
Als ich damit anfing bin ich auf das Projekt von Chris gestoßen und habe das gleich mal getestet und benutze das jetzt.
Leider ist schnell aufgefallen dass der Pi dauerhaft bei nahezu 100% Auslastung verweilt.
Nachdem ich mich aber etwas damit beschäftigte war die Ursache dafür schnell gefunden.
Die GPIOs wurden "aktiv" überwacht. Nachdem ich ein Testscript gebastelt hatte, dass die Impulse per Interrupt abfängt hat Chris seinen impsim.py dem angepasst. Seid dem läuft der Raspi unter 10%.
Ich hänge mal einige Bilder an und auch die Quellcodes für den Raspi.
Der Schaltplan (K5 ist bei mir noch überbrückt, da nicht konfiguriert) Die Unterverteilung UV_Keller: Die Ladebox im bau (Der Zähler ist in die UV_Keller gezogen) Die Befestigung der simpleEVSE Die fertige Ladebox
Die config.txt vom Raspi:
Code: Alles auswählen
# For more options and information see
# http://www.raspberrypi.org/documentation/configuration/config-txt.md
# Some settings may impact device functionality. See link above for details
# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1
# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
disable_overscan=1
# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=36
#overscan_right=36
#overscan_top=36
#overscan_bottom=36
# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=800
#framebuffer_height=480
# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1
# uncomment to force a specific HDMI mode (this will force VGA)
hdmi_group=2
hdmi_mode=1
hdmi_mode=87
hdmi_cvt 800 480 60 6 0 0 0
# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2
# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4
# uncomment for composite PAL
#sdtv_mode=2
#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi
# Additional overlays and parameters are documented /boot/overlays/README
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
Der S0-Bus des Zählers wird an GPIO 2 (+) und GROUND (-) des Pi angeschlossen (Pins 3 und 6).
Die /usr/local/bin/emob/impsim.py zählt die Impulse
Code: Alles auswählen
#!/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 = 'mail'
Abs = 'mail'
Passw = 'passwort'
smtpserv = smtplib.SMTP_SSL('server,com',465)
smtpserv.ehlo()
# In Account einloggen
smtpserv.login(Abs, Passw)
Wtxt = 'Ladestation neu gestartet'
cmsg = MIMEText(Wtxt)
cmsg['Subject'] = 'Ladestation neu gestartet'
cmsg['From'] = 'Ladestation'
cmsg['To'] = Empf
smtpserv.sendmail(Abs, [Empf], cmsg.as_string())
smtpserv.quit()
def RCtime (channel):
# print(time.strftime("Imp: %d.%m.%Y %H:%M:%S")) #Zum Debuggen
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 > 120: # Neuer Ladevorgang ab 120 sec. Pause
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.00250 # 0.00250 entspricht 400 Impulsen pro kW. 0.00125=800 Imps/kW Je nachdem was euer Zähler so macht.
dread += 0.00250
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', 'emob', 'DB-Passwort', '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', 'emob', 'DB-Passwort', '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', 'emob', 'DB-Passwort', 'DB-Name');
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('DB-Remotedomain', 'DB-Benutzer', 'DB-Passwort', 'DB-Name');
cur = con.cursor()
sql = "UPDATE DB-Benutzer.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 = 'mail'
Absender = 'mail'
Passwort = 'passwort'
smtpserver = smtplib.SMTP_SSL('server,com',465)
smtpserver.ehlo()
# In Account einloggen
smtpserver.login(Absender, Passwort)
# Text
if pload == 1:
Wert = 'Ladevorgang gestartet'
if pload == 0:
Wert = 'Ladevorgang beendet: %s kW' % 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) # Muss immer groesser sein als delta.seconds
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)
Code: Alles auswählen
#!/usr/bin/env python
import time
import subprocess
import MySQLdb as mdb
from datetime import datetime
try:
while True:
con = mdb.connect('localhost', 'emob', 'DB_Passwort', 'emob');
cur = con.cursor()
cur.execute("SELECT loading FROM emob.settings")
ldata = cur.fetchone ()
if ldata == (1L,):
subprocess.call( "vcgencmd display_power 1", shell=True )
time.sleep(600)
else:
time.sleep(5)
subprocess.call( "vcgencmd display_power 0", shell=True )
else:
time.sleep(5)
except mdb.Error, e:
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
finally:
if con:
con.close()
Code: Alles auswählen
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Exportiere Datenbank Struktur für emob
CREATE DATABASE IF NOT EXISTS `emob` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `emob`;
-- Exportiere Struktur von Tabelle emob.countings
CREATE TABLE IF NOT EXISTS `countings` (
`actual` float DEFAULT NULL,
`total` int(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Exportiere Daten aus Tabelle emob.countings: ~1 rows (ungefähr)
/*!40000 ALTER TABLE `countings` DISABLE KEYS */;
REPLACE INTO `countings` (`actual`, `total`) VALUES
(3.55, 141);
/*!40000 ALTER TABLE `countings` ENABLE KEYS */;
-- Exportiere Struktur von Tabelle emob.settings
CREATE TABLE IF NOT EXISTS `settings` (
`price` float NOT NULL,
`loading` int(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Exportiere Daten aus Tabelle emob.settings: ~1 rows (ungefähr)
/*!40000 ALTER TABLE `settings` DISABLE KEYS */;
REPLACE INTO `settings` (`price`, `loading`) VALUES
(0.2742, 1);
/*!40000 ALTER TABLE `settings` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
(Diese musste ich z.B. anpassen, da mein Provider den DB-Namen vorgibt.)
Code: Alles auswählen
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Exportiere Datenbank Struktur für ips
CREATE DATABASE IF NOT EXISTS `ips` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `ips`;
-- Exportiere Struktur von Tabelle ips.station
CREATE TABLE IF NOT EXISTS `station` (
`loading` int(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Exportiere Daten aus Tabelle ips.station: ~0 rows (ungefähr)
/*!40000 ALTER TABLE `station` DISABLE KEYS */;
REPLACE INTO `station` (`loading`) VALUES
(1);
/*!40000 ALTER TABLE `station` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
Code: Alles auswählen
#!/bin/sh
xset -dpms # disable DPMS (Energy Star) features.
xset s off # disable screen saver
xset s noblank # don't blank the video device
unclutter &
matchbox-window-manager &
midori -e Fullscreen -a http://localhost/index.php
Code: Alles auswählen
# 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
sudo xinit /home/pi/startMidori.sh &
(/bin/sleep 10 && /usr/local/bin/emob/impsim.py) &
(/bin/sleep 15 && /usr/local/bin/emob/screen.py) &
exit 0
Code: Alles auswählen
<?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'];
}
?>
Code: Alles auswählen
<?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>';
}
?>
Nochmal der Verweis auf Chris Projekt.