Merge pull request #199 from dcoutinho1328/dev-python3

Dev python3
This commit is contained in:
Thiago Alves
2023-03-01 13:52:52 -05:00
committed by GitHub
18 changed files with 329 additions and 46 deletions

View File

@@ -4,8 +4,10 @@ from sql.createTables import allTables
from sql.scripts import insert
from sql.utils import convertData
from mirror.user import UserType, UserNullable
from mirror.settings import SettingsType
from bcrypt import gensalt, hashpw
from base64 import b64encode as enc64
import json
db = dirname(__file__) + "/database.sqlite"
@@ -25,6 +27,19 @@ def getMainUserScript():
return insert("User", user)
def getDefaultSettingsScript():
staticFolder = dirname(dirname(__file__)) + "/static"
settingsFile = staticFolder + "/json/defaultSettings.json"
scripts = []
with open(settingsFile, "r") as file:
settings = json.loads(file.read())
for k, v in settings.items():
item = {"key": k, "value": v}
convertData(item, SettingsType)
scripts.append(insert("Settings", item))
return scripts
if not exists(db):
with open(db, "w"):
pass
@@ -33,4 +48,6 @@ if not exists(db):
for t in allTables:
c.execute(t)
c.execute(getMainUserScript())
for script in getDefaultSettingsScript():
c.execute(script)
c.commit()

Binary file not shown.

View File

@@ -11,7 +11,6 @@ loginManager = LoginManager()
def validateLogin(username, password):
try:
userInfo = getUserInfo(username)
except:

View File

@@ -0,0 +1,48 @@
from . import db
from sqlite3 import connect, Row
from mirror.settings import SettingsType, SettingsOptions
from sql.scripts import update, select
from sql.utils import convertData
def getSettings():
database = connect(db)
database.row_factory = Row
script = select("Settings")
try:
settings = {}
c = database.execute(script)
s = c.fetchall()
for setting in s:
settings[setting[0]] = setting[1]
database.commit()
return settings
except:
raise Exception("Failed getting settings")
def saveSettings(settings):
database = connect(db)
database.row_factory = Row
for key in SettingsOptions:
if key not in settings.keys():
settings[key] = "disabled"
scripts = []
for k, v in settings.items():
data = {"key": k, "value": v}
convertData(data, SettingsType)
filter = {"key": data.pop("key")}
scripts.append(update("Settings", data, filter))
try:
for script in scripts:
database.execute(script)
database.commit()
return settings
except:
raise Exception("Failed updating settings")

View File

@@ -8,7 +8,6 @@ from base64 import b64encode as enc64
class User:
__isAuth = True
__isActive = True
__isAnon = False

View File

@@ -10,7 +10,7 @@ blueprint = Blueprint("loginApi", __name__)
@blueprint.route("/login", methods=["GET", "POST"])
def login():
if current_user.is_authenticated:
return redirect('/dashboard', 302)
return redirect("/dashboard", 302)
return send_file("static/html/login.html")

View File

@@ -1,5 +1,8 @@
from flask import Blueprint, send_file
from flask_login import login_required
import serial.tools.list_ports
import platform
import json
blueprint = Blueprint("modbusApi", __name__)
@@ -20,3 +23,24 @@ def addDevice():
@login_required
def editDevice():
return send_file("static/html/modbus/editDevice/editModbusDevice.html")
@blueprint.route("/modbus/deviceTypes", methods=["GET", "POST"])
@login_required
def deviceTypes():
return send_file("static/json/deviceTypes.json")
@blueprint.route("/modbus/comPorts", methods=["GET", "POST"])
@login_required
def comPorts():
ports = [comport.device for comport in serial.tools.list_ports.comports()]
portNames = []
for port in ports:
portNames.append(port)
if platform.system().startswith("CYGWIN"):
portNames = list(
map(lambda x: "COM" + str(int(x.split("/dev/ttyS")[1]) + 1), portNames)
)
return json.dumps(portNames)

View File

@@ -1,5 +1,7 @@
from flask import Blueprint, send_file
from flask import Blueprint, send_file, request
from flask_login import login_required
from database.settings import getSettings, saveSettings
import json
blueprint = Blueprint("settingsApi", __name__)
@@ -7,4 +9,10 @@ blueprint = Blueprint("settingsApi", __name__)
@blueprint.route("/settings", methods=["GET", "POST"])
@login_required
def settings():
if request.method == "GET" and request.args.get("data"):
return json.dumps(getSettings())
elif request.method == "POST":
data = dict(request.form)
saveSettings(data)
return send_file("static/html/settings.html")

View File

@@ -0,0 +1,11 @@
from .classes import String
SettingsType = {"key": String, "value": String}
SettingsOptions = [
"modbus_port",
"dnp3_port",
"enip_port",
"pstorage_polling",
"start_run_mode",
]

View File

@@ -10,4 +10,10 @@ User += " salt VARCHAR(255),"
User += " CONSTRAINT pk_user PRIMARY KEY (id),"
User += " CONSTRAINT uq_user UNIQUE (username));"
allTables = [User]
# Creates Settings table
Settings = "CREATE TABLE Settings"
Settings += " (key VARCHAR(20) not null,"
Settings += " value VARCHAR(20) not null,"
Settings += " CONSTRAINT pk_settings PRIMARY KEY (key));"
allTables = [User, Settings]

View File

@@ -85,3 +85,7 @@ input[type="text"] {
display: block;
margin-top: 20px;
}
#settingsContainer {
padding: 0.01em 16px 50px 16px;
}

View File

@@ -120,14 +120,11 @@
placeholder="My Device"
/>
<label for="dev_protocol"><b>Device Type</b></label>
<select id="dev_protocol" name="device_protocol">
<option selected="selected" value="Uno">Arduino Uno</option>
<option value="Mega">Arduino Mega</option>
<option value="ESP32">ESP32</option>
<option value="ESP8266">ESP8266</option>
<option value="TCP">Generic Modbus TCP Device</option>
<option value="RTU">Generic Modbus RTU Device</option>
</select>
<select
id="dev_protocol"
name="device_protocol"
onchange="refreshSelector()"
></select>
<label for="dev_id"><b>Slave ID</b></label>
<input
type="text"
@@ -155,7 +152,11 @@
</div>
<div id="rtu-stuff">
<label for="dev_cport"><b>COM Port</b></label>
<select id="dev_cport" name="device_cport"></select>
<select
id="dev_cport"
name="device_cport"
onclick="populateCOM()"
></select>
<label for="dev_baud"><b>Baud Rate</b></label>
<input
type="text"

View File

@@ -9,7 +9,7 @@
<script src="static/javascript/settings.js"></script>
<script src="static/javascript/main.js"></script>
</head>
<body>
<body onload="onLoad()">
<div class="top">
<img
src="static/assets/openplc_logo.gif"
@@ -101,7 +101,7 @@
<a href="/startPlc" class="button start"><b>Start PLC</b></a>
</div>
<div class="mainContainer">
<div class="w3-container">
<div id="settingsContainer" class="w3-container">
<br />
<h2>Settings</h2>
<form
@@ -122,7 +122,7 @@
<input
type="text"
id="modbus_server_port"
name="modbus_server_port"
name="modbus_port"
value="502"
/>
<br />
@@ -139,7 +139,7 @@
<input
type="text"
id="dnp3_server_port"
name="dnp3_server_port"
name="dnp3_port"
value="20000"
/>
<br />
@@ -156,7 +156,7 @@
<input
type="text"
id="enip_server_port"
name="enip_server_port"
name="enip_port"
value="44818"
/>
<br />
@@ -173,7 +173,7 @@
<input
type="text"
id="pstorage_thread_poll"
name="pstorage_thread_poll"
name="pstorage_polling"
value="10"
disabled=""
/>
@@ -189,7 +189,7 @@
type="hidden"
value="false"
id="auto_run_text"
name="auto_run_text"
name="start_run_mode"
/>
<br />
<h2>Slave Devices</h2>
@@ -199,7 +199,7 @@
<input
type="text"
id="slave_polling_period"
name="slave_polling_period"
name="slave_polling"
value="100"
/>
<br />

View File

@@ -1,4 +1,85 @@
function populateDropdown() {
var tcp_stuff = document.getElementById("tcp-stuff");
var rtu_stuff = document.getElementById("rtu-stuff");
fetch("/modbus/deviceTypes")
.then((response) => {
return response.json();
})
.then((jsondata) => {
var selectedType = "rtu";
jsondata.forEach((e) => {
if (e.isSelected) {
selectedType = e.type;
}
});
switch (selectedType) {
case "rtu":
populateCOM();
tcp_stuff.style.display = "none";
rtu_stuff.style.display = "block";
break;
case "tcp":
tcp_stuff.style.display = "block";
rtu_stuff.style.display = "none";
break;
default:
break;
}
var e = document.getElementById("dev_protocol");
var tcp = document.createElement("optgroup");
tcp.label = "TCP";
var rtu = document.createElement("optgroup");
rtu.label = "RTU";
for (let hardware of jsondata) {
var option = document.createElement("option");
option.value = hardware.value;
option.selected = hardware.isSelected;
option.innerHTML = hardware.label;
if (hardware.type === "tcp") {
tcp.appendChild(option);
} else {
rtu.appendChild(option);
}
}
e.appendChild(rtu);
e.appendChild(tcp);
});
}
function populateCOM() {
fetch("/modbus/comPorts")
.then((response) => {
return response.json();
})
.then((jsondata) => {
var e = document.getElementById("dev_cport");
e.innerHTML = "";
for (let port of jsondata) {
var option = document.createElement("option");
option.value = port.toLowerCase();
option.innerHTML = port;
e.appendChild(option);
}
});
}
function refreshSelector() {
var drop_down = document.getElementById("dev_protocol");
var selected = [...drop_down.options].find((o) => o.selected);
var tcp_stuff = document.getElementById("tcp-stuff");
var rtu_stuff = document.getElementById("rtu-stuff");
if (selected.parentElement.label === "TCP") {
tcp_stuff.style.display = "block";
rtu_stuff.style.display = "none";
} else {
populateCOM();
rtu_stuff.style.display = "block";
tcp_stuff.style.display = "none";
}
}
window.onload = function () {
populateDropdown();
setupPageContent();
LoadValuesFromDB();
};

View File

@@ -1,7 +1,59 @@
window.onload = function () {
setupCheckboxes();
var checkboxes = {
modbus_port: "modbus_server",
dnp3_port: "dnp3_server",
enip_port: "enip_server",
pstorage_polling: "pstorage_thread",
start_run_mode: "auto_run",
};
function populateFields() {
fetch("/settings?data=true")
.then((response) => {
return response.json();
})
.then((jsondata) => {
for (let key in jsondata) {
var e = document.getElementsByName(key)[0];
var c = document.getElementById(checkboxes[key]);
if (key === "start_run_mode") {
c.checked = jsondata[key] === "true";
continue;
}
if (jsondata[key] === "disabled") {
if (c) c.checked = false;
} else {
if (c) c.checked = true;
e.value = jsondata[key];
}
}
setupCheckboxes();
});
}
function onLoad() {
populateFields();
setupCheckboxes();
document.getElementById("modbus_server").onchange = function () {
setupCheckboxes();
};
document.getElementById("dnp3_server").onchange = function () {
setupCheckboxes();
};
document.getElementById("enip_server").onchange = function () {
setupCheckboxes();
};
document.getElementById("pstorage_thread").onchange = function () {
setupCheckboxes();
};
document.getElementById("auto_run").onchange = function () {
setupCheckboxes();
};
}
function setupCheckboxes() {
var modbus_checkbox = document.getElementById("modbus_server");
var modbus_text = document.getElementById("modbus_server_port");
@@ -45,26 +97,6 @@ function setupCheckboxes() {
}
}
document.getElementById("modbus_server").onchange = function () {
setupCheckboxes();
};
document.getElementById("dnp3_server").onchange = function () {
setupCheckboxes();
};
document.getElementById("enip_server").onchange = function () {
setupCheckboxes();
};
document.getElementById("pstorage_thread").onchange = function () {
setupCheckboxes();
};
document.getElementById("auto_run").onchange = function () {
setupCheckboxes();
};
function validateForm() {
var modbus_checkbox = document.forms["uploadForm"]["modbus_server"].checked;
var modbus_port = document.forms["uploadForm"]["modbus_server_port"].value;
@@ -96,5 +128,6 @@ function validateForm() {
alert("Persistent Storage polling rate must be bigger than zero");
return false;
}
return true;
}

View File

@@ -0,0 +1,9 @@
{
"modbus_port": "502",
"dnp3_port": "20000",
"start_run_mode": "false",
"slave_polling": "100",
"slave_timeout": "1000",
"enip_port": "44818",
"pstorage_polling": "disabled"
}

View File

@@ -0,0 +1,44 @@
[
{
"id": 1,
"value": "arduino_uno",
"label": "Arduino Uno",
"type": "rtu",
"isSelected": false
},
{
"id": 2,
"value": "arduino_mega",
"label": "Arduino Mega",
"type": "rtu",
"isSelected": false
},
{
"id": 3,
"value": "esp32",
"label": "ESP32",
"type": "tcp",
"isSelected": false
},
{
"id": 4,
"value": "esp8266",
"label": "ESP8266",
"type": "tcp",
"isSelected": false
},
{
"id": 5,
"value": "generic_tcp",
"label": "Generic Modbus TCP Device",
"type": "tcp",
"isSelected": false
},
{
"id": 6,
"value": "generic_rtu",
"label": "Generic Modbus RTU Device",
"type": "rtu",
"isSelected": false
}
]

View File

@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
from flask import Flask, jsonify, redirect, request
from flask import Flask, redirect
from database.login import loginManager
from endpoints import blueprint as runtimeApp
from os import urandom
import json
app = Flask(__name__)
app.secret_key = urandom(12).hex()