Compare commits
3 Commits
f089edba8b
...
853a441eb9
| Author | SHA1 | Date | |
|---|---|---|---|
| 853a441eb9 | |||
| ece18aea4d | |||
| 625b6d5558 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,6 +4,7 @@ Configs/Eltex MES2424 AC - Сеть FTTB 2G, доп.txt
|
|||||||
Configs/конфиг доп 3750-52 с айпи 172.17.141.133 .txt
|
Configs/конфиг доп 3750-52 с айпи 172.17.141.133 .txt
|
||||||
DALL·E 2024-12-29 01.01.02 - Square vector logo_ A clean and minimalistic app icon for serial port management software. The design prominently features a simplified rectangular CO.ico
|
DALL·E 2024-12-29 01.01.02 - Square vector logo_ A clean and minimalistic app icon for serial port management software. The design prominently features a simplified rectangular CO.ico
|
||||||
test.py
|
test.py
|
||||||
__pycache__/TFTPServer.cpython-312.pyc
|
__pycache__/
|
||||||
Firmware/1.jpg
|
Firmware/1.jpg
|
||||||
Firmware/2
|
Firmware/2
|
||||||
|
output/
|
||||||
@@ -1,23 +1,19 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
# Это программа для копирования конфигураций на коммутаторы
|
# Это программа для копирования конфигураций на коммутаторы
|
||||||
# Программа использует библиотеку PySerial для работы с последовательными портами
|
# ------------------------------------------------------------
|
||||||
# Программа использует библиотеку PyQt5 для создания графического интерфейса
|
|
||||||
# Программа использует библиотеку PyQt5.QtWidgets для создания графического интерфейса
|
|
||||||
# Программа использует библиотеку PyQt5.QtCore для создания графического интерфейса
|
|
||||||
# Программа использует библиотеку PyQt5.QtGui для создания графического интерфейса
|
|
||||||
|
|
||||||
|
|
||||||
|
# import argparse Использовался для получения аргументов из командной строки (не используется)
|
||||||
# import argparse Использовался для получения аргументов из командной строки
|
# import platform Использовался для получения списка сетевых адаптеров (не используется)
|
||||||
# import platform Использовался для получения списка сетевых адаптеров
|
# import subprocess Использовался для получения списка сетевых адаптеров (не используется)
|
||||||
# import subprocess Использовался для получения списка сетевых адаптеров
|
# import socket не используется
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import socket
|
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -25,8 +21,6 @@ from getpass import getpass
|
|||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import (
|
from tkinter import (
|
||||||
Tk,
|
|
||||||
Frame,
|
|
||||||
StringVar,
|
StringVar,
|
||||||
END,
|
END,
|
||||||
BOTH,
|
BOTH,
|
||||||
@@ -42,6 +36,7 @@ from tkinter import ttk
|
|||||||
import serial
|
import serial
|
||||||
import serial.tools.list_ports
|
import serial.tools.list_ports
|
||||||
from serial.serialutil import SerialException
|
from serial.serialutil import SerialException
|
||||||
|
from about_window import AboutWindow
|
||||||
# from TFTPServer import TFTPServerThread
|
# from TFTPServer import TFTPServerThread
|
||||||
|
|
||||||
# Создаем необходимые папки
|
# Создаем необходимые папки
|
||||||
@@ -82,21 +77,42 @@ def settings_load():
|
|||||||
"block_size": 15, # Размер блока команд
|
"block_size": 15, # Размер блока команд
|
||||||
"prompt": ">", # Используется для определения приглашения
|
"prompt": ">", # Используется для определения приглашения
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Создаем папку Settings, если её нет
|
||||||
|
os.makedirs("Settings", exist_ok=True)
|
||||||
|
|
||||||
if not os.path.exists(SETTINGS_FILE):
|
if not os.path.exists(SETTINGS_FILE):
|
||||||
try:
|
try:
|
||||||
|
# При первом запуске создаем новый файл настроек
|
||||||
with open(SETTINGS_FILE, "w", encoding="utf-8") as f:
|
with open(SETTINGS_FILE, "w", encoding="utf-8") as f:
|
||||||
json.dump(default_settings, f, indent=4, ensure_ascii=False)
|
json.dump(default_settings, f, indent=4, ensure_ascii=False)
|
||||||
logging.info("Файл настроек создан с настройками по умолчанию.")
|
logging.info("Файл настроек создан с настройками по умолчанию.")
|
||||||
|
return default_settings
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Ошибка при создании файла настроек: {e}", exc_info=True)
|
logging.error(f"Ошибка при создании файла настроек: {e}", exc_info=True)
|
||||||
return default_settings
|
return default_settings
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Пытаемся загрузить существующие настройки
|
||||||
with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
|
with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
|
||||||
settings = json.load(f)
|
settings = json.load(f)
|
||||||
|
|
||||||
|
# Проверяем наличие всех необходимых параметров
|
||||||
|
settings_changed = False
|
||||||
for key, value in default_settings.items():
|
for key, value in default_settings.items():
|
||||||
if key not in settings:
|
if key not in settings:
|
||||||
settings[key] = value
|
settings[key] = value
|
||||||
|
settings_changed = True
|
||||||
|
|
||||||
|
# Если были добавлены новые параметры, сохраняем обновленные настройки
|
||||||
|
if settings_changed:
|
||||||
|
try:
|
||||||
|
with open(SETTINGS_FILE, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(settings, f, indent=4, ensure_ascii=False)
|
||||||
|
logging.info("Файл настроек обновлен с новыми параметрами.")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Ошибка при обновлении файла настроек: {e}", exc_info=True)
|
||||||
|
|
||||||
return settings
|
return settings
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Ошибка загрузки файла настроек: {e}", exc_info=True)
|
logging.error(f"Ошибка загрузки файла настроек: {e}", exc_info=True)
|
||||||
@@ -535,8 +551,25 @@ class SerialAppGUI(tk.Tk):
|
|||||||
self.check_first_run()
|
self.check_first_run()
|
||||||
|
|
||||||
def check_first_run(self):
|
def check_first_run(self):
|
||||||
# Проверяем, существует ли папка Settings и файл settings.json
|
"""Проверка первого запуска программы"""
|
||||||
if not os.path.exists("Settings") or not os.path.exists(SETTINGS_FILE):
|
show_settings = False
|
||||||
|
|
||||||
|
# Проверяем существование файла настроек
|
||||||
|
if not os.path.exists(SETTINGS_FILE):
|
||||||
|
show_settings = True
|
||||||
|
else:
|
||||||
|
# Проверяем содержимое файла настроек
|
||||||
|
try:
|
||||||
|
with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
|
||||||
|
settings = json.load(f)
|
||||||
|
# Если порт не настроен, считаем это первым запуском
|
||||||
|
if settings.get("port") is None:
|
||||||
|
show_settings = True
|
||||||
|
except Exception:
|
||||||
|
# Если файл поврежден или не читается, тоже показываем настройки
|
||||||
|
show_settings = True
|
||||||
|
|
||||||
|
if show_settings:
|
||||||
# Создаем папку Settings, если её нет
|
# Создаем папку Settings, если её нет
|
||||||
os.makedirs("Settings", exist_ok=True)
|
os.makedirs("Settings", exist_ok=True)
|
||||||
|
|
||||||
@@ -558,6 +591,11 @@ class SerialAppGUI(tk.Tk):
|
|||||||
file_menu.add_separator()
|
file_menu.add_separator()
|
||||||
file_menu.add_command(label="Выход", command=self.quit)
|
file_menu.add_command(label="Выход", command=self.quit)
|
||||||
|
|
||||||
|
# Меню "Справка"
|
||||||
|
help_menu = tk.Menu(menubar, tearoff=0)
|
||||||
|
menubar.add_cascade(label="Справка", menu=help_menu)
|
||||||
|
help_menu.add_command(label="О программе", command=self.open_about)
|
||||||
|
|
||||||
def open_settings(self):
|
def open_settings(self):
|
||||||
settings_window = SettingsWindow(self, self.settings, self.on_settings_changed)
|
settings_window = SettingsWindow(self, self.settings, self.on_settings_changed)
|
||||||
settings_window.transient(self)
|
settings_window.transient(self)
|
||||||
@@ -780,6 +818,11 @@ class SerialAppGUI(tk.Tk):
|
|||||||
logging.error(f"Ошибка сохранения файла: {e}", exc_info=True)
|
logging.error(f"Ошибка сохранения файла: {e}", exc_info=True)
|
||||||
messagebox.showerror("Ошибка", f"Не удалось сохранить файл:\n{e}")
|
messagebox.showerror("Ошибка", f"Не удалось сохранить файл:\n{e}")
|
||||||
|
|
||||||
|
def open_about(self):
|
||||||
|
about_window = AboutWindow(self)
|
||||||
|
about_window.transient(self)
|
||||||
|
about_window.grab_set()
|
||||||
|
|
||||||
# ==========================
|
# ==========================
|
||||||
# Парсер аргументов (не используется)
|
# Парсер аргументов (не используется)
|
||||||
# ==========================
|
# ==========================
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<ProjectGuid>5a5ba42b-743e-401d-ac33-9abfe8f095a1</ProjectGuid>
|
|
||||||
<ProjectHome>.</ProjectHome>
|
|
||||||
<StartupFile>ComConfigCopy.py</StartupFile>
|
|
||||||
<SearchPath>
|
|
||||||
</SearchPath>
|
|
||||||
<WorkingDirectory>.</WorkingDirectory>
|
|
||||||
<OutputPath>.</OutputPath>
|
|
||||||
<Name>ComConfigCopy</Name>
|
|
||||||
<RootNamespace>ComConfigCopy</RootNamespace>
|
|
||||||
<TestFramework>Pytest</TestFramework>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="ComConfigCopy.py" />
|
|
||||||
<Compile Include="test.py" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" />
|
|
||||||
<!-- Uncomment the CoreCompile target to enable the Build command in
|
|
||||||
Visual Studio and specify your pre- and post-build commands in
|
|
||||||
the BeforeBuild and AfterBuild targets below. -->
|
|
||||||
<!--<Target Name="CoreCompile" />-->
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
</Project>
|
|
||||||
100
about_window.py
Normal file
100
about_window.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, BOTH, X, BOTTOM
|
||||||
|
import webbrowser
|
||||||
|
|
||||||
|
class AboutWindow(tk.Toplevel):
|
||||||
|
def __init__(self, parent):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.title("О программе")
|
||||||
|
self.geometry("400x300")
|
||||||
|
self.resizable(False, False)
|
||||||
|
|
||||||
|
# Создаем фрейм
|
||||||
|
about_frame = ttk.Frame(self, padding="20")
|
||||||
|
about_frame.pack(fill=BOTH, expand=True)
|
||||||
|
|
||||||
|
# Заголовок
|
||||||
|
ttk.Label(
|
||||||
|
about_frame,
|
||||||
|
text="ComConfigCopy",
|
||||||
|
font=("Segoe UI", 16, "bold")
|
||||||
|
).pack(pady=(0, 10))
|
||||||
|
|
||||||
|
# Описание
|
||||||
|
ttk.Label(
|
||||||
|
about_frame,
|
||||||
|
text="Программа для копирования конфигураций на коммутаторы",
|
||||||
|
wraplength=350
|
||||||
|
).pack(pady=(0, 20))
|
||||||
|
|
||||||
|
# Версия
|
||||||
|
ttk.Label(
|
||||||
|
about_frame,
|
||||||
|
text="Версия 1.0",
|
||||||
|
font=("Segoe UI", 10)
|
||||||
|
).pack(pady=(0, 20))
|
||||||
|
|
||||||
|
# Контактная информация
|
||||||
|
contact_frame = ttk.Frame(about_frame)
|
||||||
|
contact_frame.pack(fill=X, pady=(0, 20))
|
||||||
|
|
||||||
|
# Исходный код
|
||||||
|
ttk.Label(
|
||||||
|
contact_frame,
|
||||||
|
text="Исходный код:",
|
||||||
|
font=("Segoe UI", 10, "bold")
|
||||||
|
).pack(anchor="w")
|
||||||
|
|
||||||
|
source_link = ttk.Label(
|
||||||
|
contact_frame,
|
||||||
|
text="https://gitea.filow.ru/LowaSC/ComConfigCopy",
|
||||||
|
cursor="hand2",
|
||||||
|
foreground="blue"
|
||||||
|
)
|
||||||
|
source_link.pack(anchor="w")
|
||||||
|
source_link.bind("<Button-1>", lambda e: self.open_url("https://gitea.filow.ru/LowaSC/ComConfigCopy"))
|
||||||
|
|
||||||
|
# Контакты
|
||||||
|
ttk.Label(
|
||||||
|
contact_frame,
|
||||||
|
text="\nКонтакты:",
|
||||||
|
font=("Segoe UI", 10, "bold")
|
||||||
|
).pack(anchor="w")
|
||||||
|
|
||||||
|
ttk.Label(
|
||||||
|
contact_frame,
|
||||||
|
text="Email: LowaWorkMail@gmail.com"
|
||||||
|
).pack(anchor="w")
|
||||||
|
|
||||||
|
telegram_link = ttk.Label(
|
||||||
|
contact_frame,
|
||||||
|
text="Telegram: @LowaSC",
|
||||||
|
cursor="hand2",
|
||||||
|
foreground="blue"
|
||||||
|
)
|
||||||
|
telegram_link.pack(anchor="w")
|
||||||
|
telegram_link.bind("<Button-1>", lambda e: self.open_url("https://t.me/LowaSC"))
|
||||||
|
|
||||||
|
# Кнопка закрытия
|
||||||
|
ttk.Button(
|
||||||
|
about_frame,
|
||||||
|
text="Закрыть",
|
||||||
|
command=self.destroy
|
||||||
|
).pack(side=BOTTOM, pady=(20, 0))
|
||||||
|
|
||||||
|
# Центрируем окно
|
||||||
|
self.center_window()
|
||||||
|
|
||||||
|
def center_window(self):
|
||||||
|
self.update_idletasks()
|
||||||
|
width = self.winfo_width()
|
||||||
|
height = self.winfo_height()
|
||||||
|
x = (self.winfo_screenwidth() // 2) - (width // 2)
|
||||||
|
y = (self.winfo_screenheight() // 2) - (height // 2)
|
||||||
|
self.geometry(f"{width}x{height}+{x}+{y}")
|
||||||
|
|
||||||
|
def open_url(self, url):
|
||||||
|
webbrowser.open(url)
|
||||||
Reference in New Issue
Block a user