Initial commit
This commit is contained in:
132
sc200-smart-alarm-set.py
Executable file
132
sc200-smart-alarm-set.py
Executable file
@@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
from netaddr import IPNetwork
|
||||||
|
#from netaddr import IPAddress
|
||||||
|
from xmlrpc.client import ServerProxy
|
||||||
|
import socket
|
||||||
|
import queue
|
||||||
|
import threading
|
||||||
|
import sys
|
||||||
|
import http.client
|
||||||
|
|
||||||
|
WORKERS = 10
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
Nets = [
|
||||||
|
'10.250.48.0/27',
|
||||||
|
'10.250.48.32/27',
|
||||||
|
'10.250.48.64/27',
|
||||||
|
'10.250.48.96/27',
|
||||||
|
'10.250.48.128/27',
|
||||||
|
'10.250.48.160/27',
|
||||||
|
'10.250.49.0/27',
|
||||||
|
'10.250.49.32/27',
|
||||||
|
'10.250.49.64/27',
|
||||||
|
'10.250.49.128/27',
|
||||||
|
'10.250.49.160/27',
|
||||||
|
'10.250.50.0/27',
|
||||||
|
'10.250.50.32/27',
|
||||||
|
'10.250.50.65/27',
|
||||||
|
'10.250.50.96/27',
|
||||||
|
'10.250.50.128/27',
|
||||||
|
'10.250.50.160/27',
|
||||||
|
'10.250.50.192/27',
|
||||||
|
'10.250.50.224/27',
|
||||||
|
'10.250.51.0/27',
|
||||||
|
'10.250.51.32/27',
|
||||||
|
'10.250.51.64/27',
|
||||||
|
'10.250.51.96/27',
|
||||||
|
'10.250.51.128/27',
|
||||||
|
'10.250.52.0/27',
|
||||||
|
'10.250.52.32/27',
|
||||||
|
'10.250.52.64/27',
|
||||||
|
'10.250.52.96/27',
|
||||||
|
'10.250.52.128/27',
|
||||||
|
'10.250.52.160/27',
|
||||||
|
'10.250.52.192/27'
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
Nets = sys.argv[1:]
|
||||||
|
|
||||||
|
|
||||||
|
def GetStatusCode(host, path="/"):
|
||||||
|
try:
|
||||||
|
conn = http.client.HTTPConnection(host)
|
||||||
|
conn.request("GET", path)
|
||||||
|
return conn.getresponse().status
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Worker(threading.Thread):
|
||||||
|
|
||||||
|
def __init__(self, IPs):
|
||||||
|
self.__IPs = IPs
|
||||||
|
self.parent = threading.current_thread()
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
retry = False
|
||||||
|
socket.setdefaulttimeout(5)
|
||||||
|
while 1:
|
||||||
|
IP = self.__IPs.get()
|
||||||
|
|
||||||
|
if IP is None:
|
||||||
|
break
|
||||||
|
|
||||||
|
if GetStatusCode(str(IP), "/languages") == 200:
|
||||||
|
print((self.getName() + ' processing: ' + str(IP)))
|
||||||
|
while True:
|
||||||
|
proxy = ServerProxy('http://%s/xmlrpc' % IP)
|
||||||
|
try:
|
||||||
|
Values = proxy.db.set({
|
||||||
|
'Smart-Alarm-Name:1': 'Solar',
|
||||||
|
'Smart-Alarm-Severity:1': 3,
|
||||||
|
'Smart-Alarm-DO-Mapping-A:1': 1,
|
||||||
|
'Smart-Alarm-Send-Trap:1': 1,
|
||||||
|
'Source-Alarm-Status:1': 1,
|
||||||
|
'Source-Alarm-Mapping:1': 1,
|
||||||
|
'Source-Schedule-Mapping:1': 1,
|
||||||
|
'Source-Schedule-Status:1': 1,
|
||||||
|
'Smart-Alarm-Operator:1': 0,
|
||||||
|
'Source-Schedule-First-Date-Time:1': 1481673600,
|
||||||
|
'Source-Schedule-Duration:1': 480,
|
||||||
|
'Alarm-Severity': 5,
|
||||||
|
'Alarm-DO-Mapping-A': 0,
|
||||||
|
'Alarm-Send-Trap': 0,
|
||||||
|
'Low-Float-Threshold': 50
|
||||||
|
})
|
||||||
|
except socket.timeout:
|
||||||
|
retry = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if retry:
|
||||||
|
retry = False
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
print((self.getName() + ':' + str(IP) + str(Values)))
|
||||||
|
else:
|
||||||
|
print((self.getName() + ' skipping: ' + str(IP)))
|
||||||
|
|
||||||
|
|
||||||
|
IPs = queue.Queue(0)
|
||||||
|
|
||||||
|
for i in range(WORKERS):
|
||||||
|
Worker(IPs).start()
|
||||||
|
|
||||||
|
for SubNet in Nets:
|
||||||
|
Net = IPNetwork(SubNet)
|
||||||
|
|
||||||
|
for IP in Net:
|
||||||
|
if ((IP != Net.network and IP != Net.broadcast) or
|
||||||
|
Net.broadcast is None):
|
||||||
|
#print(('Queued: ' + str(IP)))
|
||||||
|
IPs.put(IP)
|
||||||
|
|
||||||
|
for i in range(WORKERS):
|
||||||
|
IPs.put(None)
|
||||||
|
|
||||||
|
if threading.current_thread() is not threading.main_thread():
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
80
sc200-temp.py
Executable file
80
sc200-temp.py
Executable file
@@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
from xmlrpc.client import ServerProxy
|
||||||
|
import sys
|
||||||
|
import http.client
|
||||||
|
|
||||||
|
IP = sys.argv[1]
|
||||||
|
proxy = ServerProxy('http://%s/xmlrpc' % IP)
|
||||||
|
|
||||||
|
|
||||||
|
def GetStatusCode(host, path="/"):
|
||||||
|
try:
|
||||||
|
conn = http.client.HTTPConnection(host)
|
||||||
|
conn.request("GET", path)
|
||||||
|
return conn.getresponse().status
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def index():
|
||||||
|
if GetStatusCode(str(IP), "/languages") == 200:
|
||||||
|
Rectifiers = proxy.db.get(['Number-Of-Registered-Rectifiers'])[0]
|
||||||
|
print(('Batteries'))
|
||||||
|
for num in range(1, Rectifiers):
|
||||||
|
print(('Rectifier-{0}'.format(num)))
|
||||||
|
|
||||||
|
|
||||||
|
def num_indexes():
|
||||||
|
if GetStatusCode(str(IP), "/languages") == 200:
|
||||||
|
Rectifiers = proxy.db.get(['Number-Of-Registered-Rectifiers'])[0]
|
||||||
|
Rectifiers += 1
|
||||||
|
print((Rectifiers))
|
||||||
|
|
||||||
|
|
||||||
|
def get(index):
|
||||||
|
if GetStatusCode(str(IP), "/languages") == 200:
|
||||||
|
if index == 'Batteries':
|
||||||
|
query = 'Battery-Temperature'
|
||||||
|
print((proxy.db.get([query])[0]))
|
||||||
|
elif index[:10] == 'Rectifier-':
|
||||||
|
query = 'Rectifier-Heatsink-Temperature:{0}-{0}'.format(index[10:])
|
||||||
|
print((proxy.db.get([query])[0][0]))
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def query():
|
||||||
|
if GetStatusCode(str(IP), "/languages") == 200:
|
||||||
|
Rectifiers = proxy.db.get(['Number-Of-Registered-Rectifiers'])[0]
|
||||||
|
Values = proxy.db.get([
|
||||||
|
'Battery-Temperature',
|
||||||
|
'Rectifier-Heatsink-Temperature:1-%s' % Rectifiers
|
||||||
|
])
|
||||||
|
|
||||||
|
if len(Values) > 0:
|
||||||
|
outString = ""
|
||||||
|
outString += ("Batteries:%s" % Values[0])
|
||||||
|
numRect = 1
|
||||||
|
for Rectifier in Values[1]:
|
||||||
|
if type(Rectifier) is float:
|
||||||
|
outString += (" Rectifier-{0}:{1}".format(numRect,
|
||||||
|
Rectifier))
|
||||||
|
elif type(Rectifier) is dict:
|
||||||
|
outString += (" Rectifier-{0}:{1}".format(numRect,
|
||||||
|
Values[1][Rectifier['repeatLast']]))
|
||||||
|
numRect += 1
|
||||||
|
print(outString)
|
||||||
|
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
if sys.argv[2] == 'index':
|
||||||
|
index()
|
||||||
|
elif sys.argv[2] == 'num_indexes':
|
||||||
|
num_indexes()
|
||||||
|
elif sys.argv[2] == 'get' and len(sys.argv) == 4:
|
||||||
|
get(sys.argv[3])
|
||||||
|
elif sys.argv[2] == 'query':
|
||||||
|
query()
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
29
sc200.nja
Normal file
29
sc200.nja
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"mainFile": "sc200.py",
|
||||||
|
"use-tabs": false,
|
||||||
|
"venv": "",
|
||||||
|
"relatedProjects": [],
|
||||||
|
"name": "SC200",
|
||||||
|
"license": "GNU General Public License v3",
|
||||||
|
"url": "",
|
||||||
|
"pythonPath": "python3",
|
||||||
|
"preExecScript": "",
|
||||||
|
"additional_builtins": [],
|
||||||
|
"programParams": "",
|
||||||
|
"indentation": 4,
|
||||||
|
"PYTHONPATH": "",
|
||||||
|
"supported-extensions": [
|
||||||
|
".py",
|
||||||
|
".html",
|
||||||
|
".jpg",
|
||||||
|
".png",
|
||||||
|
".ui",
|
||||||
|
".css",
|
||||||
|
".json",
|
||||||
|
".js",
|
||||||
|
".ini"
|
||||||
|
],
|
||||||
|
"project-type": "Import from sources",
|
||||||
|
"postExecScript": "",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
302
sc200.py
Executable file
302
sc200.py
Executable file
@@ -0,0 +1,302 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
from netaddr import IPNetwork
|
||||||
|
#from netaddr import IPAddress
|
||||||
|
from xmlrpc.client import ServerProxy
|
||||||
|
import sqlite3
|
||||||
|
import socket
|
||||||
|
import csv
|
||||||
|
import queue
|
||||||
|
import threading
|
||||||
|
import sys
|
||||||
|
import http.client
|
||||||
|
|
||||||
|
WORKERS = 10
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
Nets = [
|
||||||
|
'10.250.48.0/27',
|
||||||
|
'10.250.48.32/27',
|
||||||
|
'10.250.48.64/27',
|
||||||
|
'10.250.48.96/27',
|
||||||
|
'10.250.48.128/27',
|
||||||
|
'10.250.48.160/27',
|
||||||
|
'10.250.49.0/27',
|
||||||
|
'10.250.49.32/27',
|
||||||
|
'10.250.49.64/27',
|
||||||
|
'10.250.49.128/27',
|
||||||
|
'10.250.49.160/27',
|
||||||
|
'10.250.50.0/27',
|
||||||
|
'10.250.50.32/27',
|
||||||
|
'10.250.50.65/27',
|
||||||
|
'10.250.50.96/27',
|
||||||
|
'10.250.50.128/27',
|
||||||
|
'10.250.50.160/27',
|
||||||
|
'10.250.50.192/27',
|
||||||
|
'10.250.50.224/27',
|
||||||
|
'10.250.51.0/27',
|
||||||
|
'10.250.51.32/27',
|
||||||
|
'10.250.51.64/27',
|
||||||
|
'10.250.51.96/27',
|
||||||
|
'10.250.51.128/27',
|
||||||
|
'10.250.52.0/27',
|
||||||
|
'10.250.52.32/27',
|
||||||
|
'10.250.52.64/27',
|
||||||
|
'10.250.52.96/27',
|
||||||
|
'10.250.52.128/27',
|
||||||
|
'10.250.52.160/27',
|
||||||
|
'10.250.52.192/27'
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
Nets = sys.argv[1:]
|
||||||
|
|
||||||
|
#Nets = [
|
||||||
|
#'10.250.48.0/27']
|
||||||
|
|
||||||
|
#print((Nets))
|
||||||
|
|
||||||
|
|
||||||
|
def Setup():
|
||||||
|
db.execute('''CREATE TABLE SC200 (
|
||||||
|
IP text PRIMARY KEY,
|
||||||
|
SiteName text,
|
||||||
|
SiteNotes text,
|
||||||
|
SerialNumber text,
|
||||||
|
FloatVoltage float,
|
||||||
|
OperatingVoltage float,
|
||||||
|
BatteryCapacity int,
|
||||||
|
ACRectifierCurrentLimit int,
|
||||||
|
HighFloatThreshold float,
|
||||||
|
EnableActiveVoltageControl bool,
|
||||||
|
EnableTemperatureCompensation bool,
|
||||||
|
TemperatureCompensationSlope float,
|
||||||
|
TemperatureCompensationReferenceTemperature float,
|
||||||
|
TemperatureCompensationUpperLimit float,
|
||||||
|
TemperatureCompensationLowerLimit float,
|
||||||
|
EnableEqualize bool,
|
||||||
|
EqualizeVoltage float,
|
||||||
|
EqualizeDuration int,
|
||||||
|
EnableFastCharge bool,
|
||||||
|
FastChargeVoltage float,
|
||||||
|
FastChargeVoltageThreshold float,
|
||||||
|
FastChargeAmpereHourThreshold int,
|
||||||
|
FastChargeRechargePercentage int,
|
||||||
|
FastChargeMaximumDuration int,
|
||||||
|
FastChargeAmpereHourStopThreshold int,
|
||||||
|
EnableBatterCurrentLimit bool,
|
||||||
|
BCLLimit int,
|
||||||
|
EnableBatterTest bool,
|
||||||
|
BatteryTestDuration int,
|
||||||
|
BatteryTestTerminationVoltage float,
|
||||||
|
LVDDisconnectVoltage float,
|
||||||
|
LVDReconnectVoltage float,
|
||||||
|
NumberOfRegisteredRectifiers int,
|
||||||
|
NumberOfRectifiersFailed int
|
||||||
|
)''')
|
||||||
|
|
||||||
|
SQL = '''CREATE TABLE AlarmNames (
|
||||||
|
SiteIP text primary key'''
|
||||||
|
for x in range(59):
|
||||||
|
SQL = SQL + ', Alarm' + repr(x) + ' text'
|
||||||
|
SQL = SQL + ')'
|
||||||
|
|
||||||
|
db.execute(SQL)
|
||||||
|
|
||||||
|
SQL = '''CREATE TABLE AlarmSeverities (
|
||||||
|
SiteIP text primary key'''
|
||||||
|
for x in range(59):
|
||||||
|
SQL = SQL + ', Alarm' + repr(x) + ' int'
|
||||||
|
SQL = SQL + ')'
|
||||||
|
|
||||||
|
db.execute(SQL)
|
||||||
|
|
||||||
|
|
||||||
|
def GetStatusCode(host, path="/"):
|
||||||
|
try:
|
||||||
|
conn = http.client.HTTPConnection(host)
|
||||||
|
conn.request("GET", path)
|
||||||
|
return conn.getresponse().status
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Worker(threading.Thread):
|
||||||
|
|
||||||
|
def __init__(self, IPs, Results):
|
||||||
|
self.__IPs = IPs
|
||||||
|
self.__Results = Results
|
||||||
|
self.parent = threading.current_thread()
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
retry = False
|
||||||
|
socket.setdefaulttimeout(5)
|
||||||
|
#print ('Started')
|
||||||
|
while 1:
|
||||||
|
IP = self.__IPs.get()
|
||||||
|
#print((self.getName()))
|
||||||
|
if IP is None:
|
||||||
|
self.__Results.put(None)
|
||||||
|
#print('Exiting')
|
||||||
|
break
|
||||||
|
|
||||||
|
#s = socket.socket()
|
||||||
|
#if s.connect_ex((str(IP), 80)) == 0:
|
||||||
|
if GetStatusCode(str(IP), "/languages") == 200:
|
||||||
|
print((self.getName() + ' processing: ' + str(IP)))
|
||||||
|
#print(('Socket OK: %s' % IP))
|
||||||
|
#print(('%s' % IP))
|
||||||
|
while True:
|
||||||
|
proxy = ServerProxy('http://%s/xmlrpc' % IP)
|
||||||
|
try:
|
||||||
|
Values = proxy.db.get([
|
||||||
|
'Site-Name',
|
||||||
|
'Site-Notes',
|
||||||
|
'Serial-Number',
|
||||||
|
'Float-Voltage',
|
||||||
|
'Operating-Voltage',
|
||||||
|
'Battery-Capacity',
|
||||||
|
'AC-Rectifier-Current-Limit',
|
||||||
|
'High-Float-Threshold',
|
||||||
|
'Enable-Active-Voltage-Control',
|
||||||
|
'Enable-Temperature-Compensation',
|
||||||
|
'Temperature-Compensation-Slope',
|
||||||
|
'Temperature-Compensation-Reference-Temperature',
|
||||||
|
'Temperature-Compensation-Upper-Limit',
|
||||||
|
'Temperature-Compensation-Lower-Limit',
|
||||||
|
'Enable-Equalize',
|
||||||
|
'Equalize-Voltage',
|
||||||
|
'Equalize-Duration',
|
||||||
|
'Enable-Fast-Charge',
|
||||||
|
'Fast-Charge-Voltage',
|
||||||
|
'Fast-Charge-Voltage-Threshold',
|
||||||
|
'Fast-Charge-Ampere-Hour-Threshold',
|
||||||
|
'Fast-Charge-Recharge-Percentage',
|
||||||
|
'Fast-Charge-Maximum-Duration',
|
||||||
|
'Fast-Charge-Ampere-Hour-Stop-Threshold',
|
||||||
|
'Enable-Battery-Current-Limit',
|
||||||
|
'BCL-Limit',
|
||||||
|
'Enable-Battery-Test',
|
||||||
|
'Battery-Test-Duration',
|
||||||
|
'Battery-Test-Termination-Voltage',
|
||||||
|
'LVD-Disconnect-Voltage:1',
|
||||||
|
'LVD-Reconnect-Voltage:1',
|
||||||
|
'Number-Of-Registered-Rectifiers',
|
||||||
|
'Number-Of-Rectifiers-Failed'
|
||||||
|
])
|
||||||
|
except socket.timeout:
|
||||||
|
retry = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if retry:
|
||||||
|
retry = False
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if len(Values) > 0:
|
||||||
|
Values.insert(0, str(IP))
|
||||||
|
self.__Results.put(['SC200', Values])
|
||||||
|
|
||||||
|
AlarmNames = ['Alarm-Name:' + repr(x) for x in range(59)]
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
Values = proxy.db.get(AlarmNames)
|
||||||
|
except socket.timeout:
|
||||||
|
retry = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if retry:
|
||||||
|
retry = False
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
Values.insert(0, str(IP))
|
||||||
|
|
||||||
|
self.__Results.put(['AlarmNames', Values])
|
||||||
|
|
||||||
|
AlarmSeverities = ['Alarm-Severity:' + repr(x)
|
||||||
|
for x in range(59)]
|
||||||
|
Values = proxy.db.get(AlarmSeverities)
|
||||||
|
|
||||||
|
Values.insert(0, str(IP))
|
||||||
|
|
||||||
|
self.__Results.put(['AlarmSeverities', Values])
|
||||||
|
#s.close()
|
||||||
|
else:
|
||||||
|
print((self.getName() + ' skipping: ' + str(IP)))
|
||||||
|
|
||||||
|
|
||||||
|
def Loader():
|
||||||
|
Count = WORKERS
|
||||||
|
c = db.cursor()
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
Row = Results.get()
|
||||||
|
if Row is None:
|
||||||
|
if Count > 1:
|
||||||
|
Count -= 1
|
||||||
|
print(Count)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print(('Loading: %s %s' % (Row[1][0], Row[0])))
|
||||||
|
SQL = 'INSERT INTO %s VALUES (' % Row[0]
|
||||||
|
for i in Row[1]:
|
||||||
|
SQL += '?,'
|
||||||
|
SQL = SQL[:-1]
|
||||||
|
SQL += ')'
|
||||||
|
|
||||||
|
c.execute(SQL, Row[1])
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def Output():
|
||||||
|
c = db.cursor()
|
||||||
|
with open('/tmp/sc200.csv', 'w', newline='') as outFile:
|
||||||
|
csvWriter = csv.writer(outFile, delimiter=',', quotechar='"',
|
||||||
|
quoting=csv.QUOTE_MINIMAL)
|
||||||
|
c.execute('''SELECT * FROM SC200 ORDER BY IP''')
|
||||||
|
csvWriter.writerow([col[0] for col in c.description])
|
||||||
|
for row in c:
|
||||||
|
csvWriter.writerow(row)
|
||||||
|
outFile.close()
|
||||||
|
|
||||||
|
with open('/tmp/sc200-alarms.csv', 'w', newline='') as outFile:
|
||||||
|
csvWriter = csv.writer(outFile, delimiter=',', quotechar='"',
|
||||||
|
quoting=csv.QUOTE_MINIMAL)
|
||||||
|
c.execute('''SELECT * FROM AlarmNames LIMIT 1''')
|
||||||
|
for row in c:
|
||||||
|
csvWriter.writerow(row)
|
||||||
|
c.execute('''SELECT * FROM AlarmSeverities''')
|
||||||
|
for row in c:
|
||||||
|
csvWriter.writerow(row)
|
||||||
|
outFile.close()
|
||||||
|
|
||||||
|
db = sqlite3.connect(':memory:')
|
||||||
|
#db = sqlite3.connect('/tmp/sc200.db')
|
||||||
|
|
||||||
|
Setup()
|
||||||
|
IPs = queue.Queue(0)
|
||||||
|
Results = queue.Queue(0)
|
||||||
|
|
||||||
|
for i in range(WORKERS):
|
||||||
|
Worker(IPs, Results).start()
|
||||||
|
|
||||||
|
for SubNet in Nets:
|
||||||
|
Net = IPNetwork(SubNet)
|
||||||
|
|
||||||
|
for IP in Net:
|
||||||
|
if IP != Net.network and IP != Net.broadcast:
|
||||||
|
#print(('Queued: ' + str(IP)))
|
||||||
|
IPs.put(IP)
|
||||||
|
|
||||||
|
for i in range(WORKERS):
|
||||||
|
IPs.put(None)
|
||||||
|
|
||||||
|
if threading.current_thread() is not threading.main_thread():
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
Loader()
|
||||||
|
Output()
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
Reference in New Issue
Block a user