mirror of
https://github.com/uhi22/pyPLC.git
synced 2024-11-10 01:05:42 +00:00
improved name consistency. Added auto response to slac_param.
This commit is contained in:
parent
b93727f011
commit
a5161a8663
2 changed files with 60 additions and 117 deletions
2
pyPlc.py
2
pyPlc.py
|
@ -49,7 +49,7 @@ worker=pyPlcWorker.pyPlcWorker(cbAddToTrace, cbShowStatus)
|
|||
nMainloops=0
|
||||
nKeystrokes=0
|
||||
while lastKey!="x":
|
||||
time.sleep(.3) # 'do some calculation'
|
||||
time.sleep(.05) # 'do some calculation'
|
||||
nMainloops+=1
|
||||
# print(str(nMainloops) + " " + str(nKeystrokes)) # show something in the console window
|
||||
root.update()
|
||||
|
|
173
pyPlcHomeplug.py
173
pyPlcHomeplug.py
|
@ -25,7 +25,13 @@
|
|||
# we see the LEDs on the adaptor shortly going completely off, completely on, and back to normal state. This
|
||||
# is the sign, that the new key was accepted. It means, the
|
||||
# adaptor is making a reset, to apply the new key.
|
||||
# 5. CM_SET_KEY and CM_GET_KEY works also when sent to broadcast address.
|
||||
# 5. CM_SET_KEY and CM_GET_KEY works also when sent to broadcast address. For both, devolo and tpLink.
|
||||
# 2022-10-18 further tests
|
||||
# 6. The devolo reports the SLAC_PARAM from the standalone-IONIQ to the wirkshark. Even in the case, when the devolo is paired to a tpLink.
|
||||
# 7. The tpLink does NOT report the SLAC_PARAM to ethernet. Bad.
|
||||
# 8. The tpLink has software from 2017, maybe the SLAC was removed at this version.
|
||||
# 9. Article regarding firmware- and configuration update: https://fitzcarraldoblog.wordpress.com/2020/07/22/updating-the-powerline-adapters-in-my-home-network/
|
||||
|
||||
|
||||
import pcap
|
||||
|
||||
|
@ -114,23 +120,17 @@ class pyPlcHomeplug():
|
|||
print("HomePlug protocol")
|
||||
return blIsHomePlug
|
||||
|
||||
def fillSourceMac(self, mac):
|
||||
self.mytransmitbuffer[6]=mac[0]
|
||||
self.mytransmitbuffer[7]=mac[1]
|
||||
self.mytransmitbuffer[8]=mac[2]
|
||||
self.mytransmitbuffer[9]=mac[3]
|
||||
self.mytransmitbuffer[10]=mac[4]
|
||||
self.mytransmitbuffer[11]=mac[5]
|
||||
def fillSourceMac(self, mac, offset=6): # at offset 6 in the ethernet frame, we have the source MAC
|
||||
# we can give a different offset, to re-use the MAC also in the data area
|
||||
for i in range(0, 6):
|
||||
self.mytransmitbuffer[offset+i]=mac[i]
|
||||
|
||||
def fillDestinationMac(self, mac):
|
||||
self.mytransmitbuffer[0]=mac[0]
|
||||
self.mytransmitbuffer[1]=mac[1]
|
||||
self.mytransmitbuffer[2]=mac[2]
|
||||
self.mytransmitbuffer[3]=mac[3]
|
||||
self.mytransmitbuffer[4]=mac[4]
|
||||
self.mytransmitbuffer[5]=mac[5]
|
||||
def fillDestinationMac(self, mac, offset=0): # at offset 0 in the ethernet frame, we have the destination MAC
|
||||
# we can give a different offset, to re-use the MAC also in the data area
|
||||
for i in range(0, 6):
|
||||
self.mytransmitbuffer[offset+i]=mac[i]
|
||||
|
||||
def cleanTransmitBuffer(self):
|
||||
def cleanTransmitBuffer(self): # fill the complete ethernet transmit buffer with 0x00
|
||||
for i in range(0, len(self.mytransmitbuffer)):
|
||||
self.mytransmitbuffer[i]=0
|
||||
|
||||
|
@ -149,7 +149,7 @@ class pyPlcHomeplug():
|
|||
# calculates the MMTYPE (base value + lower two bits), see Table 11-2 of homeplug spec
|
||||
return (self.myreceivebuffer[16]<<8) + self.myreceivebuffer[15]
|
||||
|
||||
def composeTestFrameGetSwReq(self):
|
||||
def composeGetSwReq(self):
|
||||
# GET_SW.REQ request, as used by the win10 laptop
|
||||
self.mytransmitbuffer = bytearray(60)
|
||||
self.cleanTransmitBuffer()
|
||||
|
@ -167,7 +167,7 @@ class pyPlcHomeplug():
|
|||
self.mytransmitbuffer[18]=0xB0 #
|
||||
self.mytransmitbuffer[19]=0x52 #
|
||||
|
||||
def composeTestFrameSetKey(self, variation=0):
|
||||
def composeSetKey(self, variation=0):
|
||||
# CM_SET_KEY.REQ request
|
||||
# From example trace from catphish https://openinverter.org/forum/viewtopic.php?p=40558&sid=9c23d8c3842e95c4cf42173996803241#p40558
|
||||
# Table 11-88 in the homeplug_av21_specification_final_public.pdf
|
||||
|
@ -213,7 +213,7 @@ class pyPlcHomeplug():
|
|||
self.mytransmitbuffer[41]+=variation # to try different NMKs
|
||||
# and three remaining zeros
|
||||
|
||||
def composeTestFrameGetKey(self):
|
||||
def composeGetKey(self):
|
||||
# CM_GET_KEY.REQ request
|
||||
# from https://github.com/uhi22/plctool2/blob/master/listen_to_eth.c
|
||||
# and homeplug_av21_specification_final_public.pdf
|
||||
|
@ -249,25 +249,21 @@ class pyPlcHomeplug():
|
|||
self.mytransmitbuffer[34]=0x00 #
|
||||
self.mytransmitbuffer[35]=0x00 # 17 PMN Protocol message number
|
||||
|
||||
def composeTestFrameSlacReq(self):
|
||||
# SLAC request, as it was recorded 2021-12-17 WP charger 2
|
||||
def composeSlacParamReq(self):
|
||||
# SLAC_PARAM request, as it was recorded 2021-12-17 WP charger 2
|
||||
self.mytransmitbuffer = bytearray(60)
|
||||
self.cleanTransmitBuffer()
|
||||
# Destination MAC
|
||||
self.fillDestinationMac(MAC_BROADCAST)
|
||||
|
||||
# Source MAC
|
||||
self.fillSourceMac(MAC_IONIQ)
|
||||
|
||||
# Protocol
|
||||
self.mytransmitbuffer[12]=0x88 # Protocol HomeplugAV
|
||||
self.mytransmitbuffer[13]=0xE1
|
||||
|
||||
self.mytransmitbuffer[14]=0x01 # version
|
||||
self.mytransmitbuffer[15]=0x64 # SLAC_PARAM.REQ
|
||||
|
||||
self.mytransmitbuffer[16]=0x60 #
|
||||
self.mytransmitbuffer[17]=0x00 #
|
||||
self.mytransmitbuffer[17]=0x00 # 2 bytes fragmentation information. 0000 means: unfragmented.
|
||||
self.mytransmitbuffer[18]=0x00 #
|
||||
self.mytransmitbuffer[19]=0x00 #
|
||||
self.mytransmitbuffer[20]=0x00 #
|
||||
|
@ -279,103 +275,41 @@ class pyPlcHomeplug():
|
|||
self.mytransmitbuffer[26]=0xC3 #
|
||||
self.mytransmitbuffer[27]=0x00 #
|
||||
self.mytransmitbuffer[28]=0x00 #
|
||||
# rest is 00
|
||||
|
||||
self.mytransmitbuffer[29]=0x00 # rest is 0
|
||||
self.mytransmitbuffer[30]=0x00 #
|
||||
self.mytransmitbuffer[31]=0x00 #
|
||||
self.mytransmitbuffer[32]=0x00 #
|
||||
self.mytransmitbuffer[33]=0x00 #
|
||||
self.mytransmitbuffer[34]=0x00 #
|
||||
self.mytransmitbuffer[35]=0x00 #
|
||||
self.mytransmitbuffer[36]=0x00 #
|
||||
self.mytransmitbuffer[37]=0x00 #
|
||||
self.mytransmitbuffer[38]=0x00 #
|
||||
self.mytransmitbuffer[39]=0x00 #
|
||||
self.mytransmitbuffer[40]=0x00 #
|
||||
self.mytransmitbuffer[41]=0x00 #
|
||||
self.mytransmitbuffer[42]=0x00 #
|
||||
self.mytransmitbuffer[43]=0x00 #
|
||||
self.mytransmitbuffer[44]=0x00 #
|
||||
self.mytransmitbuffer[45]=0x00 #
|
||||
self.mytransmitbuffer[46]=0x00 #
|
||||
self.mytransmitbuffer[47]=0x00 #
|
||||
self.mytransmitbuffer[48]=0x00 #
|
||||
self.mytransmitbuffer[49]=0x00 #
|
||||
self.mytransmitbuffer[50]=0x00 #
|
||||
self.mytransmitbuffer[51]=0x00 #
|
||||
self.mytransmitbuffer[52]=0x00 #
|
||||
self.mytransmitbuffer[53]=0x00 #
|
||||
self.mytransmitbuffer[54]=0x00 #
|
||||
self.mytransmitbuffer[55]=0x00 #
|
||||
self.mytransmitbuffer[56]=0x00 #
|
||||
self.mytransmitbuffer[57]=0x00 #
|
||||
self.mytransmitbuffer[58]=0x00 #
|
||||
self.mytransmitbuffer[59]=0x00 #
|
||||
|
||||
def composeTestFrameSlacResp(self):
|
||||
def composeSlacParamCnf(self):
|
||||
self.mytransmitbuffer = bytearray(60)
|
||||
self.cleanTransmitBuffer()
|
||||
# Destination MAC
|
||||
self.fillDestinationMac(MAC_IONIQ)
|
||||
|
||||
# Source MAC
|
||||
self.fillSourceMac(MAC_ALPI)
|
||||
|
||||
self.fillSourceMac(MAC_RANDOM)
|
||||
# Protocol
|
||||
self.mytransmitbuffer[12]=0x88 # Protocol HomeplugAV
|
||||
self.mytransmitbuffer[13]=0xE1
|
||||
|
||||
self.mytransmitbuffer[14]=0x01 # version
|
||||
self.mytransmitbuffer[15]=0x65 # SLAC_PARAM.confirm
|
||||
|
||||
self.mytransmitbuffer[16]=0x60 #
|
||||
self.mytransmitbuffer[17]=0x00 #
|
||||
self.mytransmitbuffer[17]=0x00 # 2 bytes fragmentation information. 0000 means: unfragmented.
|
||||
self.mytransmitbuffer[18]=0x00 #
|
||||
self.mytransmitbuffer[19]=0xff #
|
||||
self.mytransmitbuffer[19]=0xff # 19-24 sound target
|
||||
self.mytransmitbuffer[20]=0xff #
|
||||
self.mytransmitbuffer[21]=0xff #
|
||||
self.mytransmitbuffer[22]=0xff #
|
||||
self.mytransmitbuffer[23]=0xff #
|
||||
self.mytransmitbuffer[24]=0xff #
|
||||
self.mytransmitbuffer[25]=0x0A #
|
||||
self.mytransmitbuffer[26]=0x06 #
|
||||
self.mytransmitbuffer[27]=0x01 #
|
||||
self.mytransmitbuffer[28]=0x04 #
|
||||
self.mytransmitbuffer[29]=0x65 #
|
||||
self.mytransmitbuffer[30]=0x65 #
|
||||
self.mytransmitbuffer[31]=0x00 #
|
||||
|
||||
self.mytransmitbuffer[32]=0x64 #
|
||||
self.mytransmitbuffer[33]=0xC3 #
|
||||
self.mytransmitbuffer[25]=0x0A # sound count
|
||||
self.mytransmitbuffer[26]=0x06 # timeout
|
||||
self.mytransmitbuffer[27]=0x01 # resptype
|
||||
self.fillDestinationMac(MAC_IONIQ, 28) # forwarding_sta, same as PEV MAC, plus 2 bytes 00 00
|
||||
self.mytransmitbuffer[34]=0x00 #
|
||||
self.mytransmitbuffer[35]=0x00 #
|
||||
self.mytransmitbuffer[36]=0x04 #
|
||||
self.mytransmitbuffer[37]=0x65 #
|
||||
self.mytransmitbuffer[38]=0x65 #
|
||||
self.mytransmitbuffer[39]=0x00 #
|
||||
self.mytransmitbuffer[40]=0x64 #
|
||||
self.mytransmitbuffer[41]=0xC3 #
|
||||
self.fillDestinationMac(MAC_IONIQ, 36) # runid, same as PEV MAC, plus 2 bytes 00 00
|
||||
self.mytransmitbuffer[42]=0x0 #
|
||||
self.mytransmitbuffer[43]=0x0 #
|
||||
self.mytransmitbuffer[44]=0x0 #
|
||||
self.mytransmitbuffer[45]=0x0 #
|
||||
self.mytransmitbuffer[46]=0x0 #
|
||||
self.mytransmitbuffer[47]=0x0 #
|
||||
# rest is 00
|
||||
|
||||
self.mytransmitbuffer[48]=0x0 #
|
||||
self.mytransmitbuffer[49]=0x0 #
|
||||
self.mytransmitbuffer[50]=0x0 #
|
||||
self.mytransmitbuffer[51]=0x0 #
|
||||
self.mytransmitbuffer[52]=0x0 #
|
||||
self.mytransmitbuffer[53]=0x0 #
|
||||
self.mytransmitbuffer[54]=0x0 #
|
||||
self.mytransmitbuffer[55]=0x0 #
|
||||
self.mytransmitbuffer[56]=0x0 #
|
||||
self.mytransmitbuffer[57]=0x0 #
|
||||
self.mytransmitbuffer[58]=0x0 #
|
||||
self.mytransmitbuffer[59]=0x0 #
|
||||
|
||||
def composeTestFrameDHCP(self):
|
||||
def composeDHCP(self):
|
||||
# DHCP discover, to check whether this "normal" package arrives on the other side
|
||||
self.mytransmitbuffer = bytearray(379)
|
||||
self.cleanTransmitBuffer()
|
||||
|
@ -417,32 +351,32 @@ class pyPlcHomeplug():
|
|||
def sendTestFrame(self, selection):
|
||||
|
||||
if (selection=="1"):
|
||||
self.composeTestFrameSlacReq()
|
||||
self.addToTrace("transmitting TestFrame SlacReq...")
|
||||
self.composeSlacParamReq()
|
||||
self.addToTrace("transmitting SLAC_PARAM.REQ...")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
if (selection=="2"):
|
||||
self.composeTestFrameSlacResp()
|
||||
self.addToTrace("transmitting TestFrame SlacResp...")
|
||||
self.composeSlacParamCnf()
|
||||
self.addToTrace("transmitting SLAC_PARAM.CNF...")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
if (selection=="S"):
|
||||
self.composeTestFrameGetSwReq()
|
||||
self.addToTrace("transmitting TestFrame GetSwReq...")
|
||||
self.composeGetSwReq()
|
||||
self.addToTrace("transmitting GetSwReq...")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
if (selection=="s"):
|
||||
self.composeTestFrameSetKey(1)
|
||||
self.addToTrace("transmitting TestFrame SET_KEY.REQ (key 1)")
|
||||
self.composeSetKey(1)
|
||||
self.addToTrace("transmitting SET_KEY.REQ (key 1)")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
if (selection=="t"):
|
||||
self.composeTestFrameSetKey(2)
|
||||
self.addToTrace("transmitting TestFrame SET_KEY.REQ (key 2)")
|
||||
self.composeSetKey(2)
|
||||
self.addToTrace("transmitting SET_KEY.REQ (key 2)")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
if (selection=="D"):
|
||||
self.composeTestFrameDHCP()
|
||||
self.addToTrace("transmitting TestFrame broken DHCP")
|
||||
self.composeDHCP()
|
||||
self.addToTrace("transmitting broken DHCP")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
if (selection=="G"):
|
||||
self.composeTestFrameGetKey()
|
||||
self.addToTrace("transmitting TestFrame GET_KEY")
|
||||
self.composeGetKey()
|
||||
self.addToTrace("transmitting GET_KEY")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
|
||||
def evaluateGetKeyCnf(self):
|
||||
|
@ -454,6 +388,13 @@ class pyPlcHomeplug():
|
|||
s=s+hex(self.NID[i])+ " "
|
||||
print("From GetKeyCnf, got network ID (NID) " + s)
|
||||
|
||||
def evaluateSlacParamReq(self):
|
||||
# We received a SLAC_PARAM request from the PEV. This is the initiation of a SLAC procedure.
|
||||
# If we want to emulate an EVSE, we want to answer.
|
||||
self.composeSlacParamCnf()
|
||||
self.addToTrace("transmitting CM_SLAC_PARAM.CNF")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
|
||||
def evaluateSlacMatchCnf(self):
|
||||
# The SLAC_MATCH.CNF contains the NMK and the NID.
|
||||
# We extract this information, so that we can use it for the CM_SET_KEY afterwards.
|
||||
|
@ -470,7 +411,7 @@ class pyPlcHomeplug():
|
|||
s=s+hex(self.NMK[i])+ " "
|
||||
print("From SlacMatchCnf, got network membership key (NMK) " + s)
|
||||
# use the extracted NMK and NID to set the key in the adaptor:
|
||||
self.composeTestFrameSetKey(0)
|
||||
self.composeSetKey(0)
|
||||
self.addToTrace("transmitting CM_SET_KEY.REQ")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
|
||||
|
@ -481,6 +422,8 @@ class pyPlcHomeplug():
|
|||
self.evaluateGetKeyCnf()
|
||||
if (mmt == CM_SLAC_MATCH + MMTYPE_CNF):
|
||||
self.evaluateSlacMatchCnf()
|
||||
if (mmt == CM_SLAC_PARAM + MMTYPE_REQ):
|
||||
self.evaluateSlacParamReq()
|
||||
|
||||
|
||||
def findEthernetAdaptor(self):
|
||||
|
|
Loading…
Reference in a new issue