From 6db498feb6635c2bcbdc015ef01003dac233734b Mon Sep 17 00:00:00 2001 From: uhi22 Date: Fri, 25 Nov 2022 12:17:53 +0100 Subject: [PATCH] v.02 Resolved address error in SDP. Gave for time for SDP and TCP. Added docu. Fixed parameter bug. --- pyPlcHomeplug.py | 4 +++- pyPlcIpv6.py | 3 +++ pyPlcTcpSocket.py | 2 +- pyPlcWorker.py | 4 ++++ readme.md | 15 +++++++++++---- ...5_v0.2_ABB_until_ChargeParamDiscovery.pcapng | Bin 0 -> 95288 bytes .../2022-11-25_v0.2_alpi_SDP_ok_TCP_fail.pcapng | Bin 0 -> 31212 bytes 7 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 results/2022-11-25_v0.2_ABB_until_ChargeParamDiscovery.pcapng create mode 100644 results/2022-11-25_v0.2_alpi_SDP_ok_TCP_fail.pcapng diff --git a/pyPlcHomeplug.py b/pyPlcHomeplug.py index 56f6d20..19e3e81 100644 --- a/pyPlcHomeplug.py +++ b/pyPlcHomeplug.py @@ -908,7 +908,9 @@ class pyPlcHomeplug(): if ((not self.isEvseModemFound()) and (not self.isSimulationMode)): self.nEvseModemMissingCounter+=1 self.addToTrace("[PEVSLAC] No EVSE seen (yet). Still waiting for it.") - if (self.nEvseModemMissingCounter>5): + # At the Alpitronic we measured, that it takes 7s between the SlacMatchResponse and + # the chargers modem reacts to GetKeyRequest. So we should wait here at least 10s. + if (self.nEvseModemMissingCounter>10): if (self.isSimulationMode): self.addToTrace("[PEVSLAC] No EVSE modem. But this is fine, we are in SimulationMode.") else: diff --git a/pyPlcIpv6.py b/pyPlcIpv6.py index 4e17df1..3199074 100644 --- a/pyPlcIpv6.py +++ b/pyPlcIpv6.py @@ -249,6 +249,8 @@ class ipv6handler(): self.IpRequest[5] = plen & 0xFF self.IpRequest[6] = 0x11 # next level protocol, 0x11 = UDP in this case self.IpRequest[7] = 0x0A # hop limit + # We are the PEV. So the EvccIp is our own link-local IP address. + self.EvccIp = self.addressManager.getLinkLocalIpv6Address("bytearray") for i in range(0, 16): self.IpRequest[8+i] = self.EvccIp[i] # source IP address for i in range(0, 16): @@ -351,6 +353,7 @@ class ipv6handler(): # self.SeccIp = [ 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0xe0, 0xad, 0x99, 0xac, 0x52, 0xeb, 0x85, 0xd3 ] # 16 bytes, a default IPv6 address for the vehicle # todo: On EVSE side, extract the vehicles IP address from the SDP communication + # Just a default, will be overwritten later: self.EvccIp = [ 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x06, 0x65, 0x65, 0xff, 0xfe, 0, 0x64, 0xC3 ] #self.ownMac = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 ] # 6 bytes own MAC default. Should be overwritten before use. self.ownMac = self.addressManager.getLocalMacAddress() diff --git a/pyPlcTcpSocket.py b/pyPlcTcpSocket.py index 17e0e57..d9dddaf 100644 --- a/pyPlcTcpSocket.py +++ b/pyPlcTcpSocket.py @@ -63,7 +63,7 @@ class pyPlcTcpClientSocket(): self.sock.setblocking(0) # make this socket non-blocking, so that the recv function will immediately return self.isConnected = True except socket.error as e: - self.addToTrace("connection failed", e) + self.addToTrace("connection failed" + str(e)) self.isConnected = False def transmit(self, msg): diff --git a/pyPlcWorker.py b/pyPlcWorker.py index 4913e19..e65b14e 100644 --- a/pyPlcWorker.py +++ b/pyPlcWorker.py @@ -9,6 +9,7 @@ import fsmEvse import fsmPev from pyPlcModes import * import addressManager +import time class pyPlcWorker(): @@ -43,6 +44,9 @@ class pyPlcWorker(): def callbackReadyForTcp(self, status): if (status==1): self.workerAddToTrace("[PLCWORKER] Network is established, ready for TCP.") + self.workerAddToTrace("[PLCWORKER] Waiting....") + time.sleep(5) + self.workerAddToTrace("[PLCWORKER] now...") if (self.oldAvlnStatus==0): self.oldAvlnStatus = 1 if (self.mode == C_PEV_MODE): diff --git a/readme.md b/readme.md index eb7384f..d6f99b4 100644 --- a/readme.md +++ b/readme.md @@ -282,6 +282,15 @@ version request broadcast message, to find out, whether we have at least two hom car and one for the charger). If this is fulfilled, we should use the SDP to discover the chargers IPv6 address. But this is not yet implemented. +### 2022-11-25 v0.2 On ABB charger until ChargeParamDiscoveryRequest +- With Win10 notebook in PevMode, tested on Alpitronics HPC and ABB Triple charger. On the Alpi, the SLAC and SDP works. The TCP connection fails. On ABB, the SLAC, SDP and TCP works. Also the protocol negotiation works. We come until ChargeParamDiscoveryReqest. +- Log messages are sent via UDP port 514 as broadcast, like Syslog messages. The Wireshark shows them as readable text, so we have the actual communication between car and charger in the trace and also the debug log. +- Example pcap in results/2022-11-25_v0.2_ABB_until_ChargeParamDiscovery.pcapng +- With Win10 notebook in EvseMode, tested on the Ioniq car. It comes until the CurrentDemandRequest. +- For using Raspberry in PevMode without display, there is now the pevNoGui.py, which can be auto-started by configuring a service which calls starter.sh, and this calls starter.py (this is still expermental). +- The old Raspberry model B needs 90s from power-on until it sends the first log messages. Means, the boot is quite slow. +- Raspberry in PevMode and Win10 notebook in EvseMode work well together until the PreCharge. + ## Biggest Challenges - [*ListenMode*] Find a way to enable the sniffer mode or monitor mode in the AR7420. Seems to be not included in the public qca/open-plc-utils. @@ -294,12 +303,10 @@ functions Monitor() and Sniffer(), but these are included from a path ../nda/ wh Any idea how to enable full-transparency of the AR7420? -- [all modes] replace the fix-configured addresses (MAC, IP) in the python script by the real one from the operating system - ## Other open topics - [*EvseMode*] [*PevMode*] Fill V2G messages as far as needed, to convince the car to accept it. -- [*PevMode*] Implement SDP to get the chargers IPv6 address -- [*PevMode*] Testing on real charger +- [*PevMode*] Find out TCP connection issue on Alpitronics +- [*PevMode*] Implement TCP connection retry - improve docu (update layer diagram, improve hardware docu, add link to evse which provides the 5% PWM) - Resolve the todo-markers in the code - (and much more) diff --git a/results/2022-11-25_v0.2_ABB_until_ChargeParamDiscovery.pcapng b/results/2022-11-25_v0.2_ABB_until_ChargeParamDiscovery.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..261f362a20cdf6c71d69265d90b0f33d5ecbc4db GIT binary patch literal 95288 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 sKTyT(onYgCC^-Rss~G*ITdyXj