Skip to content

Commit 9445cd5

Browse files
committed
bump to 0.3.0
fix the incompatibility issue with Pytes 'C' models -- closes #9 introduced mqtt authentication (better compatibility to Home Assistant) -- closes #7 introduced statistics -- i.e overall info for the bank -- closes #10 small refactoring
1 parent 26e6c8b commit 9445cd5

File tree

1 file changed

+112
-35
lines changed

1 file changed

+112
-35
lines changed

pytes_serial.py

Lines changed: 112 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525

2626
MQTT_active = config.get('MQTT', 'MQTT_active')
2727
MQTT_broker = config.get('MQTT', 'MQTT_broker')
28+
MQTT_port = int(config.get('MQTT', 'MQTT_port'))
29+
MQTT_username = config.get('MQTT', 'MQTT_username')
30+
MQTT_password = config.get('MQTT', 'MQTT_password')
2831

2932
start_time = time.time()
3033
up_time = time.time()
@@ -33,7 +36,7 @@
3336
errors_no = 0 # used to count no of errors and to calculate %
3437
errors = 'false'
3538

36-
print('PytesSerial build: v0.2.3_20230114')
39+
print('PytesSerial build: v0.3.0_20230123')
3740

3841
# ------------------------functions area----------------------------
3942
def log (str) :
@@ -45,23 +48,32 @@ def log (str) :
4548
return
4649
except Exception as e:
4750
print("Errorhandling: double error in EventLog", e)
48-
51+
4952
def parsing_serial():
50-
global errors
51-
if ser.is_open != True:
52-
ser.open()
53-
time.sleep(0.2)
54-
print ('...serial opened')
55-
for power in range (1, powers+1): # do the loop for each battery
56-
try:
57-
# parsing pwr x commmand - reading power bank x
58-
line_str = "" # clear line_str
59-
line = "" # clear line
60-
power_bytes = bytes(str(power), 'ascii') # convert to bytes
61-
ser.write(b'pwr '+ power_bytes + b'\n') # write on serial port 'pwr x' command
53+
global errors
54+
volt_st = None # initiate non critical variable to ensure various firmaware combatibility
55+
current_st = None
56+
temp_st = None
57+
coul_st = None
58+
soh_st = None
59+
heater_st = None
60+
bat_events = None
61+
power_events = None
62+
sys_events = None
63+
64+
try:
65+
if ser.is_open != True:
66+
ser.open()
67+
print ('...serial opened')
68+
69+
for power in range (1, powers+1): # do the loop for each battery
70+
line_str = "" # clear line_str
71+
line = "" # clear line
72+
power_bytes = bytes(str(power), 'ascii') # convert to bytes
73+
ser.write(b'pwr '+ power_bytes + b'\n') # write on serial port 'pwr x' command
6274
ser.flush()
6375

64-
time.sleep(0.2) # calm down a bit ...
76+
time.sleep(0.5) # calm down a bit ...
6577
buffer = ser.in_waiting
6678
print ('...writing complete ', 'in buffer:', buffer)
6779

@@ -73,12 +85,12 @@ def parsing_serial():
7385
print('...suspicious data set, trying again')
7486
errors = 'true'
7587

76-
log('*'+str(errors_no)+'*'+str(buffer)+'**>'+str(line)) # [DPO] for debug purpose remark the line
88+
log('*'+str(errors_no)+'*'+str(buffer)+'**>'+str(line)) # [DPO] for debug purpose
7789

7890
if ser.is_open == True:
7991
ser.close()
8092
print ('...serial closed')
81-
return # do not move forward if no end of the parsing group detected
93+
return # do not move forward if no end of the parsing group detected
8294

8395
if line_str[1:18] == 'Voltage :': voltage = int(line_str[19:27])/1000
8496
if line_str[1:18] == 'Current :': current = int(line_str[19:27])/1000
@@ -93,7 +105,7 @@ def parsing_serial():
93105
if line_str[1:18] == 'Heater Status :': heater_st = line_str[19:27]
94106
if line_str[1:18] == 'Bat Events :': bat_events = int(line_str[19:27],16)
95107
if line_str[1:18] == 'Power Events :': power_events = int(line_str[19:27],16)
96-
if line_str[1:18] == 'System Fault :': sys_events = int(line_str[19:27],16)
108+
if line_str[1:18] == 'System Fault :': sys_events = int(line_str[19:27],16)
97109
if line_str[1:18] == 'Command completed':
98110
break
99111

@@ -132,28 +144,62 @@ def parsing_serial():
132144
'sys_events': sys_events}
133145

134146
pwr.append(pwr_array)
135-
136-
except Exception as e:
137-
print("...serial parsing error: " + str(e))
138-
errors = 'true'
139-
140-
log('*'+str(errors_no)+'*'+str(buffer)+'**>'+str(line)) # [DPO] for debug purpose remark the line
141147

142-
if ser.is_open == True:
143-
ser.close()
144-
print ('...serial closed')
145-
return
148+
statistics()
149+
150+
print ('...serial parsing: ok')
151+
152+
except Exception as e:
153+
print("...serial parsing error: " + str(e))
154+
errors = 'true'
155+
if ser.is_open == True:
156+
ser.close()
157+
print ('...serial closed')
158+
return
159+
160+
log('*'+str(errors_no)+'*'+str(buffer)+'**>'+str(line)) # [DPO] for debug purpose
146161

147-
print ('...serial parsing: ok')
162+
def statistics():
163+
global sys_voltage
164+
global sys_current
165+
global sys_soc
166+
global sys_temp
167+
global sys_basic_st
168+
sys_voltage = 0
169+
sys_current = 0
170+
sys_soc = 0
171+
sys_temp = 0
172+
sys_basic_st = ""
173+
174+
for power in range (1, powers+1):
175+
sys_voltage = sys_voltage + pwr[power-1]['voltage'] # vontage will be the average of all batteries
176+
sys_current = round((sys_current + pwr[power-1]['current']),3) # current will be sum of all banks
177+
sys_soc = sys_soc + pwr[power-1]['soc'] # soc will be the average of all batteries
178+
sys_temp = sys_temp + pwr[power-1]['temperature'] # temperature will be the average of all batteries
179+
180+
sys_voltage = round((sys_voltage / powers), 3)
181+
sys_soc = int(sys_soc / powers)
182+
sys_basic_st = pwr[0]['basic_st'] # status will be the master status
183+
sys_temp = round((sys_temp / powers), 1)
148184

149185
def json_serialize():
150186
global errors
151187
global json_data
152188
try:
153-
json_data={'relay_local_time':TimeStamp, 'serial_uptime':uptime, 'pytes':pwr}
189+
json_data={'relay_local_time':TimeStamp,
190+
'serial_uptime':uptime,
191+
'powers' : powers,
192+
'voltage': sys_voltage,
193+
'current': sys_current,
194+
'temperature': sys_temp,
195+
'soc': sys_soc,
196+
'basic_st': sys_basic_st,
197+
'pytes':pwr}
198+
154199
with open(output_path + 'pytes_status.json', 'w') as outfile:
155200
json.dump(json_data, outfile)
156-
print('...json creation: ok')
201+
print('...json creation: ok')
202+
157203
except Exception as e:
158204
print('...json serailization error: ' + str(e))
159205
errors = 'true'
@@ -208,13 +254,39 @@ def maria_db():
208254

209255
def mqtt_discovery():
210256
try:
257+
MQTT_auth = None
258+
if len(MQTT_username) >0:
259+
MQTT_auth = { 'username': MQTT_username, 'password': MQTT_password }
211260
msg ={}
212261
config = 1
213262
names =["pytes_current", "pytes_voltage" , "pytes_temperature", "pytes_soc", "pytes_status"]
214263
ids =["current", "voltage" , "temperature", "soc", "basic_st"] #do not change the prefix "pytes_"
215264
dev_cla =["current", "voltage", "temperature", "battery","None"]
216265
unit_of_meas =["A","v","°C", "%",""]
217266

267+
# define system sensors
268+
for n in range(5):
269+
state_topic ="homeassistant/sensor/pytes/"+str(config)+"/config"
270+
msg ["name"] = names[n]
271+
msg ["stat_t"] = "homeassistant/sensor/pytes/state"
272+
msg ["uniq_id"] = "pytes_"+ids[n]
273+
if dev_cla[n] != "None":
274+
msg ["dev_cla"] = dev_cla[n]
275+
msg ["unit_of_meas"] = unit_of_meas[n]
276+
msg ["val_tpl"] = "{{ value_json." + ids[n]+ "}}"
277+
msg ["dev"] = {"identifiers": ["pytes"],"manufacturer": "PYTES","model": "E-Box48100R","name": "pytes_ebox","sw_version": "1.0"}
278+
279+
message = json.dumps(msg)
280+
publish.single(state_topic, message, hostname=MQTT_broker, port= MQTT_port, auth=MQTT_auth, qos=0, retain=True)
281+
282+
b = "...mqtt auto discovery initialization :" + str(round(config/(5*powers+5)*100)) +" %"
283+
print (b, end="\r")
284+
285+
msg ={}
286+
config = config +1
287+
time.sleep(2)
288+
289+
# define individual batteries sensors
218290
for power in range (1, powers+1):
219291
for n in range(5):
220292
state_topic ="homeassistant/sensor/pytes/"+str(config)+"/config"
@@ -228,23 +300,28 @@ def mqtt_discovery():
228300
msg ["dev"] = {"identifiers": ["pytes"],"manufacturer": "PYTES","model": "E-Box48100R","name": "pytes_ebox","sw_version": "1.0"}
229301

230302
message = json.dumps(msg)
231-
publish.single(state_topic, message, hostname=MQTT_broker, qos=0, retain=True)
303+
publish.single(state_topic, message, hostname=MQTT_broker, port= MQTT_port, auth=MQTT_auth, qos=0, retain=True)
232304

305+
b = "...mqtt auto discovery initialization :" + str(round(config/(5*powers+5)*100)) +" %"
306+
print (b, end="\r")
307+
233308
msg ={}
234309
config = config +1
235-
b = "...mqtt auto discovery initialization" + "." * config
236-
print (b, end="\r")
237310
time.sleep(2)
311+
238312
print("...mqtt auto discovery initialization completed")
239313

240314
except Exception as e:
241315
print('...mqtt_discovery failed' + str(e))
242316

243317
def mqtt_publish():
244318
try:
319+
MQTT_auth = None
320+
if len(MQTT_username) >0:
321+
MQTT_auth = { 'username': MQTT_username, 'password': MQTT_password }
245322
state_topic = "homeassistant/sensor/pytes/state"
246323
message = json.dumps(json_data)
247-
publish.single(state_topic, message, hostname=MQTT_broker)
324+
publish.single(state_topic, message, hostname=MQTT_broker, port=MQTT_port, auth=MQTT_auth)
248325
print ('...mqtt publish : ok')
249326

250327
except Exception as e:

0 commit comments

Comments
 (0)