Ladebox für Elektroautos

Antworten
Benutzeravatar
benny
Forum Junkie
Beiträge: 463
Registriert: 11.06.2016 - 11:51
Hat sich bedankt: 11 Mal
Geschlecht:

Ladebox für Elektroautos

Beitrag von benny »

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)
Ladebox.pdf
(19.02 KiB) 507-mal heruntergeladen
Die Unterverteilung UV_Keller:
UV-Keller_2.jpg
Die Ladebox im bau (Der Zähler ist in die UV_Keller gezogen)
Ladebox_3.jpg
Die Befestigung der simpleEVSE 8-)
Ladebox_EVSE.jpg
Die fertige Ladebox
Ladebox_4.jpg

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)
Die /usr/local/bin/emob/screen.py schaltet den Monitor ein und mit Verzögerung nach dem Ladevorgang wieder aus.

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()
Die Importdatei emobsql.sql für den lokalen MySQL-Server

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 */;
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.)

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 */;
Die /home/pi/startMidori.sh Datei für den Windowmanager (hier matchbox) und den Browserstart.

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
Die /etc/rc.local zum steuern des Autostart

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

Hier die der Code, der in die externe Webseite gehört:

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'];
}

?>
...und hier die eigentliche Anzeige:

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>';
    }
?>
Die lokale Webseite.
www.zip
(2.56 KiB) 452-mal heruntergeladen

Nochmal der Verweis auf Chris Projekt.
Bis dann,
benny

PS: Ich werde in Zukunft keinen Support mehr per PN leisten. Bitte eröffnet ein Thema im Hilfebereich, oder wo auch immer eure Fragen hin passen.
Benutzeravatar
benny
Forum Junkie
Beiträge: 463
Registriert: 11.06.2016 - 11:51
Hat sich bedankt: 11 Mal
Geschlecht:

Re: Ladebox für Elektroautos

Beitrag von benny »

Ich muss überlegen, ob ich die Ladesäule kastriere und sie auf max. 22kW beschneide. :roll: :oops: :evil: :evil:

Weitere Infos für Interessierte gibt's im Blog
Bis dann,
benny

PS: Ich werde in Zukunft keinen Support mehr per PN leisten. Bitte eröffnet ein Thema im Hilfebereich, oder wo auch immer eure Fragen hin passen.
Benutzeravatar
benny
Forum Junkie
Beiträge: 463
Registriert: 11.06.2016 - 11:51
Hat sich bedankt: 11 Mal
Geschlecht:

Re: Ladebox für Elektroautos

Beitrag von benny »

Z.Z. bekomme ich keine Mail beim beenden des Ladevorgangs....

Normalerweise sollte sowas kommen:
Ladevorgang beendet: 6.4825 kW
Na ich werde mal beizeiten forschen...
Bis dann,
benny

PS: Ich werde in Zukunft keinen Support mehr per PN leisten. Bitte eröffnet ein Thema im Hilfebereich, oder wo auch immer eure Fragen hin passen.
Benutzeravatar
benny
Forum Junkie
Beiträge: 463
Registriert: 11.06.2016 - 11:51
Hat sich bedankt: 11 Mal
Geschlecht:

Re: Ladebox für Elektroautos

Beitrag von benny »

Ich habe den Fehler dafür gefunden.
Er zählte gar nicht mehr.
Es gab einen Impuls beim starten der Ladung, der wohl reichte um dem Raspi zu sagen dass die Ladung gestartet wurde, doch alle weiteren Impulse (Schließer schließt 400x/kWh) wurden nicht gezählt.

Die physische Verbindung zwischen GPIOs und dem Zähler war vertauscht. Diese sind am Zähler mit + und - Bezeichnet worauf ich nicht achtete.
Ich bin davon ausgegangen, daß das, wie bei einem normalen Schließer, egal ist. War wohl nicht der Fall. :shock:
Ich hatte vor einiger Zeit die Verkabelung getauscht. Vorher war die wohl "Richtig" angeschlossen und danach "Falsch".
Der Anfangsimpuls kam also wohl nur durch Induktion zustande.
Bis dann,
benny

PS: Ich werde in Zukunft keinen Support mehr per PN leisten. Bitte eröffnet ein Thema im Hilfebereich, oder wo auch immer eure Fragen hin passen.
Benutzeravatar
benny
Forum Junkie
Beiträge: 463
Registriert: 11.06.2016 - 11:51
Hat sich bedankt: 11 Mal
Geschlecht:

Re: Ladebox für Elektroautos

Beitrag von benny »

Ich habe immer wieder Meldungen über einen gestarteten Ladevorgang bekommen.
Vermutet hatte ich, das der Zähler ab und an auch ohne Last einen Impuls abgegeben hat.

Daraufhin habe ich vor ca. einen Monat zwei weitere Installationsschütze verbaut die die Steuerleitungen vom Zähler zum Raspi beidseits trennt solange nicht geladen wird.

Die Falschmeldungen sind zwar weniger geworden, doch sind sie nicht weg. :shock:

Jetzt bleiben nur noch zwei mögliche Ursachen...
Entweder der Raspi ist das Problem (Hardware/Software) oder es wird ein Impuls in die Steuerleitung induziert. :cry:
Bis dann,
benny

PS: Ich werde in Zukunft keinen Support mehr per PN leisten. Bitte eröffnet ein Thema im Hilfebereich, oder wo auch immer eure Fragen hin passen.
Antworten