229 lines
8.8 KiB
Python
229 lines
8.8 KiB
Python
import snap7
|
|
import struct
|
|
import time
|
|
import os
|
|
from snap7.util import get_int, get_dint, get_real, get_string
|
|
|
|
# Configurazione PLC
|
|
PLC_IP = '127.0.0.1'
|
|
# PLC_IP = '192.168.124.43'
|
|
RACK = 0
|
|
SLOT = 2
|
|
|
|
# Codici Colore ANSI
|
|
GREEN = "\033[92m"
|
|
RED = "\033[91m"
|
|
RESET = "\033[0m"
|
|
|
|
class SiemensClient:
|
|
def __init__(self, ip, rack, slot):
|
|
self.client = snap7.client.Client()
|
|
self.rack = rack
|
|
self.slot = slot
|
|
self.ip = ip
|
|
|
|
def connect(self):
|
|
try:
|
|
self.client.connect(self.ip, self.rack, self.slot)
|
|
print(f"Connesso a {self.ip}")
|
|
return True
|
|
except Exception as e:
|
|
print(f"Errore di connessione: {e}")
|
|
return False
|
|
|
|
def read_db900_db901(self):
|
|
# Lettura DB900 (16KB)
|
|
start_time = time.perf_counter()
|
|
#~nel test leggo solo 40 valori + counter iniziale
|
|
db900_data = self.client.db_read(900, 0, 404)
|
|
end_time = time.perf_counter()
|
|
db900_duration = (end_time - start_time) * 1000
|
|
|
|
# Lettura DB901 (38 byte)
|
|
start_time_901 = time.perf_counter()
|
|
db901_data = self.client.db_read(901, 0, 38)
|
|
end_time_901 = time.perf_counter()
|
|
db901_duration = (end_time_901 - start_time_901) * 1000
|
|
|
|
# Parsing DB901 (DINT e Bit)
|
|
status_901 = db901_data[0]
|
|
acquisizione_901 = (status_901 & 0x02) != 0
|
|
fine_acq_901 = (status_901 & 0x04) != 0
|
|
pronti_901 = (status_901 & 0x08) != 0
|
|
|
|
# Parsing DB900 (DINT) - Primi 21 valori (DBD0-DBD80)
|
|
# DBD0: Numero misure (DINT)
|
|
# num_misure = struct.unpack('<I', db900_data[0:4])[0]
|
|
num_misure = get_dint(db900_data,0)
|
|
|
|
# Array misure (da DBD4 in poi)
|
|
valori_db900 = []
|
|
for i in range(21):
|
|
offset = (i * 4)
|
|
if offset + 4 <= 164:
|
|
valori_db900.append(get_dint(db900_data,offset))
|
|
else:
|
|
valori_db900.append(0)
|
|
|
|
return {
|
|
"db900_data": valori_db900,
|
|
"db900_num_misure": num_misure,
|
|
"db901_status": {
|
|
"acquisizione": acquisizione_901,
|
|
"pronti": pronti_901,
|
|
"fine_acq": fine_acq_901
|
|
},
|
|
"db901_duration": db901_duration,
|
|
"db900_duration": db900_duration
|
|
}
|
|
|
|
def read_db100(self):
|
|
start_time = time.perf_counter()
|
|
data = self.client.db_read(100, 0, 192)
|
|
end_time = time.perf_counter()
|
|
duration = (end_time - start_time) * 1000 # in ms
|
|
|
|
# Parsing Status Bits (DBD0)
|
|
status_bytes = data[0:4]
|
|
# Bit 0: Acquisizione (1=On, 0=Off)
|
|
acquisizione = (status_bytes[0] & 0x01) != 0
|
|
# Bit 8 (primo bit del secondo byte)
|
|
# Nota: Se il PLC mappa il bit 9 come il primo bit del byte 1,
|
|
# lo shift è 0x80 (10000000 in binario)
|
|
pronti = (status_bytes[1] & 0x80) != 0
|
|
|
|
# Parsing REAL (32-bit Float) in BIG-ENDIAN (>)
|
|
params = {}
|
|
params['x_iniziale'] = get_real(data,4)
|
|
params['x_finale'] = get_real(data,8)
|
|
params['limite_sup'] = get_real(data,12)
|
|
params['limite_inf'] = get_real(data,16)
|
|
params['tipo_lettura'] = get_real(data,20)
|
|
params['conteggio'] = get_real(data,24)
|
|
params['param_arco'] = get_real(data,28)
|
|
params['param_extra1'] = get_real(data,32)
|
|
params['param_extra2'] = get_real(data,36)
|
|
params['param_extra3'] = get_real(data,40)
|
|
|
|
# X_Live: DBD56 (Byte 56-59), Y_Live: DBD60 (Byte 60-63)
|
|
params['x_live'] = get_real(data,56)
|
|
params['y_live'] = get_real(data,60)
|
|
|
|
# Tempo di lettura della DB100
|
|
params['db100_time'] = duration
|
|
|
|
strings = {
|
|
"Comm": get_string(data,64),
|
|
"Art": get_string(data,96),
|
|
"IdCont": get_string(data,128),
|
|
"Altro": get_string(data,160)
|
|
}
|
|
|
|
return {
|
|
"status": {"acquisizione": acquisizione, "pronti": pronti},
|
|
"params": params,
|
|
"strings": strings
|
|
}
|
|
|
|
def read_db101(self):
|
|
start_time = time.perf_counter()
|
|
data = self.client.db_read(101, 0, 160)
|
|
end_time = time.perf_counter()
|
|
duration = (end_time - start_time) * 1000 # in ms
|
|
|
|
try:
|
|
values = struct.unpack('>40f', data)
|
|
return values, duration
|
|
except Exception as e:
|
|
print(f"Errore lettura DB101: {e}")
|
|
return None, duration
|
|
|
|
def disconnect(self):
|
|
self.client.disconnect()
|
|
|
|
def clear_screen():
|
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
|
|
if __name__ == "__main__":
|
|
plc = SiemensClient(PLC_IP, RACK, SLOT)
|
|
if plc.connect():
|
|
try:
|
|
while True:
|
|
clear_screen()
|
|
db100_data = plc.read_db100()
|
|
db101_data, db101_time = plc.read_db101()
|
|
db900_data = plc.read_db900_db901()
|
|
|
|
print("=" * 60)
|
|
print(f" PLC MONITOR - {PLC_IP} ")
|
|
print("=" * 60)
|
|
print(f" STATO: Acquisizione={db100_data['status']['acquisizione']} | Pronti={db100_data['status']['pronti']}")
|
|
print(f" LATENZA: DB100={db100_data['params']['db100_time']:.2f}ms | DB901={db900_data['db901_duration']:.2f}ms")
|
|
print("-" * 60)
|
|
print(f" VALORI LIVE:")
|
|
print(f" X_Live (DBD56): {db100_data['params']['x_live']:>10.4f}")
|
|
print(f" Y_Live (DBD60): {db100_data['params']['y_live']:>10.4f}")
|
|
print("-" * 60)
|
|
print(f" DATI STRINGHE:")
|
|
print(f" Commessa: {db100_data['strings']['Comm']}")
|
|
print(f" Articolo: {db100_data['strings']['Art']}")
|
|
print(f" IdCont: {db100_data['strings']['IdCont']}")
|
|
print(f" Altro: {db100_data['strings']['Altro']}")
|
|
print("-" * 60)
|
|
|
|
# Gestione DB101 con grafico a barre centrato
|
|
if db101_data:
|
|
# Prendi i primi 20 valori
|
|
data_subset = db101_data[:20]
|
|
|
|
print(f" VISUALIZZAZIONE DB101 (Primi {len(data_subset)}):")
|
|
if data_subset:
|
|
# Scala fissa basata sui tuoi dati (-2..+2)
|
|
scale_max = 2.0
|
|
|
|
for i, val in enumerate(data_subset):
|
|
# Calcola larghezza barra (max 15 caratteri per lato del centro)
|
|
bar_len = int((abs(val) / scale_max) * 15)
|
|
bar_len = min(bar_len, 15)
|
|
bar = "█" * bar_len
|
|
|
|
if val > 0:
|
|
# Cresce verso destra: [ |███████████████]
|
|
left_side = "-" * 15
|
|
right_side = bar + "-" * (15 - bar_len)
|
|
color = GREEN
|
|
line = f" [{i+1:02d}] {left_side}|{color}{right_side}{RESET} {val:>8.4f}"
|
|
elif val < 0:
|
|
# Cresce verso sinistra: [-------█████████████| ]
|
|
left_side = "-" * (15 - bar_len) + bar
|
|
right_side = "-" * 15
|
|
color = RED
|
|
line = f" [{i+1:02d}] {color}{left_side}{RESET}|{right_side} {val:>8.4f}"
|
|
else:
|
|
# Valore zero: [ | ]
|
|
line = f" [{i+1:02d}] {'-' * 15}|{'-' * 15} {val:>8.4f}"
|
|
|
|
print(line)
|
|
|
|
print("-" * 60)
|
|
print(f" DATI DB900 (Primi {len(db900_data['db900_data'])} DINT):")
|
|
# Mostra i primi 21 valori della DB900
|
|
for i, val in enumerate(db900_data['db900_data']):
|
|
# Il primo valore (index 0) è il numero di misure
|
|
if i == 0:
|
|
print(f" [000] Num. Misure: {val}")
|
|
else:
|
|
print(f" [{i:03d}] Valore DINT: {val}")
|
|
|
|
print("-" * 60)
|
|
|
|
# Campionamento dinamico
|
|
if db100_data['status']['acquisizione']:
|
|
time.sleep(0.5)
|
|
else:
|
|
time.sleep(2.0)
|
|
except KeyboardInterrupt:
|
|
print("\nInterruzione utente.")
|
|
finally:
|
|
plc.disconnect()
|