a1405a6bbecda02b921121ed270d92b54b4bf344
[sven/scripts.git] / home / enverbridge.py
1 #!/usr/bin/env python3
2
3 # This script can be used to configure the Inverter IDs
4 # on an Envertech EnverBridge device. This is a replacement
5 # for the "SetID" programm provided as a Win32 executable at
6 # http://www.envertec.com/uploads/bigfiles/Set%20ID.zip
7 # Tested online with the EnverBridge 202 and Inverters which
8 # have the same serial nummer on both labels.
9 #
10 # Logic seems the be the following:
11 # Take the inverter id, append the char 9 to 16 of the 16 char
12 # serial number. Do this for every pair of serial numbers.
13 # Sent this string in one UDP paket to the broadcast address on
14 # port 8765. Wait for a response paket to the broadcast address
15 # on port 8764.
16
17 from optparse import OptionParser
18 import socket
19 import sys
20 import re
21
22 parser = OptionParser(usage="usage: %prog [options] MIIDs")
23 parser.add_option("-b", "--bid",
24                   action="store",
25                   type="int",
26                   dest="bid",
27                   help="Serial Number of your EnverBridge")
28 (options, args) = parser.parse_args()
29
30
31 def validateMIID(miids):
32     error = False
33     idpattern = re.compile(r"^CN[0-9]{14}$")
34     for id in miids:
35         print("Validating MIID", id)
36         if not idpattern.search(id):
37             print("Error: Invalid MIID", id)
38             error = True
39
40     if error:
41         print("Validation error, check your MIIDs, exiting")
42         sys.exit(23)
43
44
45 def buildMIIDList(miids):
46     msg = ""
47     for id in miids:
48         msg = msg + id[8:16]
49     return msg
50
51
52 # minimal input validation
53 if len(args) < 1:
54     print("Error: missing MIIDs, provide at least one inverter serial")
55     sys.exit(22)
56
57 validateMIID(args)
58
59 # assemble message string and convert to bytes
60 message = str(options.bid) + buildMIIDList(args)
61 message = message.encode()
62 print('Sending to EnverBridge with ID', options.bid)
63
64 # Create a UDP client socket w/ broadcast
65 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
66 sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
67
68 # Create a UDP server socket we bind to to listen for broadcasts
69 ssock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
70 ssock.bind(('', 8764))
71
72 try:
73     # Send data via broadcast to port 8765
74     print('Sending {!r}'.format(message))
75     server_address = ('<broadcast>', 8765)
76     sent = sock.sendto(message, server_address)
77
78     # Receive response on port 8764
79     print('Waiting to receive')
80     data, server = ssock.recvfrom(8764)
81     print('Received {!r}'.format(data))
82
83 finally:
84     print('Closing sockets')
85     sock.close()
86     ssock.close()