Pre-release v1.0
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
test/
|
||||
temp/
|
||||
test.py
|
||||
|
||||
# ---> Python
|
||||
|
||||
224
handlers.py
Normal file
224
handlers.py
Normal file
@@ -0,0 +1,224 @@
|
||||
import asyncio
|
||||
import socket
|
||||
import time
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from aiogram import Router, F
|
||||
from aiogram import Bot, Dispatcher, types
|
||||
from aiogram.filters.command import Command
|
||||
from aiogram.types import FSInputFile
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
from aiogram.fsm.state import StatesGroup, State
|
||||
from aiogram.utils.chat_action import ChatActionSender
|
||||
#from aiogram.types import BufferedInputFile
|
||||
|
||||
import configparser
|
||||
from asyncpg_lite import DatabaseManager
|
||||
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
|
||||
import lib.OCer as OCer
|
||||
import serial
|
||||
|
||||
router = Router()
|
||||
|
||||
async def get_user_list(db_url, deletion_password, table_name):
|
||||
try:
|
||||
db_manager = DatabaseManager(db_url=db_url, deletion_password=deletion_password)
|
||||
data = []
|
||||
async with db_manager as manager:
|
||||
one_data = await manager.select_data(table_name=table_name)
|
||||
for i in one_data:
|
||||
data.append(i)
|
||||
logging.info(f"Fetched {len(data)} records from the database.")
|
||||
return data
|
||||
|
||||
except Exception as err:
|
||||
logging.error(err)
|
||||
pass
|
||||
|
||||
def init(Bot):
|
||||
global config, bot, logger, some_open_ports, zxc
|
||||
|
||||
bot = Bot
|
||||
#consts&confs
|
||||
config = configparser.ConfigParser()
|
||||
#bc_calculator = lomka.BCCCalculator()
|
||||
some_open_ports = serial.tools.list_ports.comports()
|
||||
|
||||
#load config file
|
||||
config.read('config.ini')
|
||||
# device_hwid = config['DEFAULT']['device_hwid']
|
||||
# baudrate = config['DEFAULT']['baudrate']
|
||||
|
||||
#log section
|
||||
logging.basicConfig(
|
||||
level=logging.INFO if config['DEFAULT']['debug'] == "false" else logging.DEBUG,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler('lastest.log'),
|
||||
logging.StreamHandler()])
|
||||
logger = logging.getLogger(socket.gethostname())
|
||||
|
||||
zxc = OCer.caser(device_hwid="PID=1A86:7523", baudrate=9600,
|
||||
config=config, logger=logger)
|
||||
zxc.set_controller_number(1)
|
||||
zxc.set_port_device()
|
||||
|
||||
|
||||
main_kb = [
|
||||
[types.KeyboardButton(text="Выбрать контроллер")],
|
||||
[types.KeyboardButton(text="Открыть секцию")],
|
||||
[types.KeyboardButton(text="Статус секции")],
|
||||
[types.KeyboardButton(text="Статус ВСЕХ секций")],
|
||||
[types.KeyboardButton(text="Открыть ВСЕ секции")],
|
||||
[types.KeyboardButton(text="Контакты")]]
|
||||
|
||||
keyboardos = types.ReplyKeyboardMarkup(keyboard=main_kb, resize_keyboard=True,
|
||||
input_field_placeholder="amogus life420")
|
||||
|
||||
class Form(StatesGroup):
|
||||
input_controller = State()
|
||||
input_section = State()
|
||||
input_status_section = State()
|
||||
input_status_section_all = State()
|
||||
input_approve = State()
|
||||
|
||||
@router.message(Command("start"))
|
||||
async def cmd_start(message: types.Message):
|
||||
|
||||
keyboard = types.ReplyKeyboardMarkup(keyboard=main_kb, resize_keyboard=True,
|
||||
input_field_placeholder="Выберите действие...", is_persistent=True)
|
||||
|
||||
await message.answer(f"{message.from_user.id}\n",
|
||||
reply_markup=keyboard)
|
||||
|
||||
@router.message(F.text.lower() == "выбрать контроллер")
|
||||
async def choose_controller(message: types.Message, state: FSMContext):
|
||||
kb = [
|
||||
[types.KeyboardButton(text="Домой")]
|
||||
]
|
||||
keyboard = types.ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True,
|
||||
input_field_placeholder="amogus life420")
|
||||
|
||||
await message.reply("Определите номер управляемого контроллера", reply_markup=keyboard)
|
||||
|
||||
await state.set_state(Form.input_controller)
|
||||
|
||||
@router.message(F.text, Form.input_controller)
|
||||
async def set_controller_number(message: types.Message, state: FSMContext):
|
||||
await state.update_data(confirm=message.text)
|
||||
user_data = await state.get_data()
|
||||
|
||||
try:
|
||||
await zxc.set_controller_capacity(int(user_data["confirm"]))
|
||||
await message.reply(f"Контроллер ({user_data["confirm"]}) выбран успешно!",
|
||||
reply_markup=keyboardos)
|
||||
except Exception as e:
|
||||
await message.reply(f"Возникло исключение(ошибка): {e}", reply_markup=keyboardos)
|
||||
await state.clear()
|
||||
|
||||
@router.message(F.text.lower() == "статус всех секций")
|
||||
async def status_all_sections(message: types.Message, state: FSMContext):
|
||||
|
||||
cool_data = await zxc.READ_ALL_CELLS()
|
||||
|
||||
await message.reply(f"{cool_data}", reply_markup=keyboardos)
|
||||
await state.clear()
|
||||
|
||||
@router.message(F.text.lower() == "открыть все секции")
|
||||
async def open_all_sections(message: types.Message, state: FSMContext):
|
||||
kb = [
|
||||
[types.KeyboardButton(text="Продолжить")],
|
||||
[types.KeyboardButton(text="Домой")]
|
||||
]
|
||||
keyboard = types.ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True,
|
||||
input_field_placeholder="amogus life420")
|
||||
|
||||
await message.reply("Данная операция откроет ВСЕ секции доступные контроллеру.\nПродолжить?", reply_markup=keyboard)
|
||||
|
||||
await state.set_state(Form.input_approve)
|
||||
|
||||
@router.message(F.text, Form.input_approve)
|
||||
async def open_all_sections_confirm(message: types.Message, state: FSMContext):
|
||||
await state.update_data(confirm=message.text)
|
||||
user_data = await state.get_data()
|
||||
|
||||
if str(user_data["confirm"]).lower() == "продолжить":
|
||||
try:
|
||||
cool_data = await zxc.OPEN_ALL_CELLS_LEGACY(True)
|
||||
await message.reply(f"Статус ячеек:\n{cool_data}",
|
||||
reply_markup=keyboardos)
|
||||
except Exception as e:
|
||||
await message.reply(f"Возникло исключение(ошибка): {e}", reply_markup=keyboardos)
|
||||
await state.clear()
|
||||
|
||||
@router.message(F.text.lower() == "контакты")
|
||||
async def contact_info(message: types.Message):
|
||||
keyboard = types.ReplyKeyboardMarkup(keyboard=main_kb, resize_keyboard=True,
|
||||
input_field_placeholder="amogus life420")
|
||||
await message.reply("Настучать админу: \n" \
|
||||
"Discord: Valo#1234 | @valoker\n" \
|
||||
"GitHub: @Valoker\n" \
|
||||
"Telegram: @Valoka", reply_markup=keyboard)
|
||||
|
||||
@router.message(F.text.lower() == "домой")
|
||||
async def home(message: types.Message, state: FSMContext):
|
||||
await message.answer(reply_markup=keyboardos,
|
||||
text="Меню")
|
||||
await state.clear()
|
||||
|
||||
@router.message(F.text.lower() == "открыть секцию")
|
||||
async def open_section(message: types.Message, state: FSMContext):
|
||||
kb = [
|
||||
[types.KeyboardButton(text="Домой")]
|
||||
]
|
||||
keyboard = types.ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True,
|
||||
input_field_placeholder="amogus life420")
|
||||
|
||||
await message.reply("Отправьте номер секции для открытия..", reply_markup=keyboard)
|
||||
await state.set_state(Form.input_section)
|
||||
|
||||
@router.message(F.text, Form.input_section)
|
||||
async def open_section_number(message: types.Message, state: FSMContext):
|
||||
await state.update_data(confirm=message.text)
|
||||
user_data = await state.get_data()
|
||||
|
||||
try:
|
||||
await zxc.open_cell(int(user_data["confirm"]))
|
||||
await message.reply(f"Секция ({user_data["confirm"]}) контроллера " \
|
||||
f"({zxc.controller_number}) открыта.",
|
||||
reply_markup=keyboardos)
|
||||
except Exception as e:
|
||||
await message.reply(f"Возникло исключение(ошибка): {e}", reply_markup=keyboardos)
|
||||
await state.clear()
|
||||
|
||||
@router.message(F.text.lower() == "статус секции")
|
||||
async def get_section_status(message: types.Message, state: FSMContext):
|
||||
kb = [
|
||||
[types.KeyboardButton(text="Домой")]
|
||||
]
|
||||
keyboard = types.ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True,
|
||||
input_field_placeholder="amogus life420")
|
||||
|
||||
await message.reply("Отправьте номер желаемой секции..", reply_markup=keyboard)
|
||||
|
||||
await state.set_state(Form.input_status_section)
|
||||
|
||||
@router.message(F.text, Form.input_status_section)
|
||||
async def get_section_status_fin(message: types.Message, state: FSMContext):
|
||||
await state.update_data(confirm=message.text)
|
||||
user_data = await state.get_data()
|
||||
|
||||
try:
|
||||
controller_data = await zxc.read_controller(cell_number=int(user_data["confirm"]))
|
||||
await message.reply(f"Секция ({user_data["confirm"]}) контроллера " \
|
||||
f"({zxc.controller_number}) со статусом: {controller_data[0]["CURRENT_STATUS"]}. \n{controller_data}",
|
||||
reply_markup=keyboardos)
|
||||
except Exception as e:
|
||||
await message.reply(f"Возникло исключение(ошибка): {e}", reply_markup=keyboardos)
|
||||
await state.clear()
|
||||
|
||||
156
lib/OCer.py
156
lib/OCer.py
@@ -1,6 +1,4 @@
|
||||
import serial.tools.list_ports
|
||||
import time
|
||||
import configparser
|
||||
import logging
|
||||
import socket
|
||||
import lib.lomka as lomka
|
||||
@@ -28,7 +26,7 @@ class caser:
|
||||
config.read(config_name)
|
||||
self.device_hwid = config['DEFAULT']['device_hwid']
|
||||
self.baudrate = config['DEFAULT']['baudrate']
|
||||
self.controller_capacity = config['DEFAULT']['controller_capacity']
|
||||
self.controller_capacity = int(config['DEFAULT']['controller_capacity'])
|
||||
|
||||
# узнать какое исключение вызывается конкретно, ибо нужно проверять каждое по отдельности
|
||||
except:
|
||||
@@ -41,8 +39,9 @@ class caser:
|
||||
self.comport: str # только адрес
|
||||
self.active_comport = serial.tools.list_ports.comports()[0] # объект порта (dummy)
|
||||
self.controller_number: bytes = 1
|
||||
self.connection : serial.Serial
|
||||
#self.connection : serial.Serial
|
||||
self.async_connection : tuple
|
||||
self.instance_error_count : int = 0
|
||||
|
||||
# Определение базовых констант/команд
|
||||
self.default_consts = {True: 17,
|
||||
@@ -62,14 +61,6 @@ class caser:
|
||||
self.logger.info(f"Found the correct port: {port.device}")
|
||||
return str(port.device)
|
||||
|
||||
def set_controller_capacity(self, capacity: int):
|
||||
'''Устанавливает количество доступных замков'''
|
||||
#сделать автоматом
|
||||
if capacity:
|
||||
self.controller_capacity = capacity
|
||||
else:
|
||||
self.controller_capacity = 18
|
||||
|
||||
def set_port_device(self, port_device=None):
|
||||
'''Устанавливает com port'''
|
||||
|
||||
@@ -84,13 +75,13 @@ class caser:
|
||||
self.controller_number = hex(controller_number)
|
||||
|
||||
async def send_command(self, cell_number : int, command: int,
|
||||
bytes_count=15, header=138):
|
||||
bytes_count=5, header=138):
|
||||
try:
|
||||
# active_comport = serial.Serial(self.comport, baudrate=self.baudrate, timeout=2)
|
||||
reader, writer = await serial_asyncio.open_serial_connection(
|
||||
url=self.comport,
|
||||
baudrate=self.baudrate
|
||||
)
|
||||
baudrate=self.baudrate,
|
||||
timeout=2)
|
||||
|
||||
self.logger.info(f"Connected to {self.comport}")
|
||||
|
||||
@@ -111,91 +102,124 @@ class caser:
|
||||
writer.write(data_string)
|
||||
return await reader.read(bytes_count)
|
||||
|
||||
except Exception as error:
|
||||
raise error
|
||||
|
||||
async def read_controller(self, cell_number : int, command=51,
|
||||
header=128, bytes_count=5):
|
||||
try:
|
||||
# active_comport = serial.Serial(self.comport, baudrate=self.baudrate, timeout=2)
|
||||
reader, writer = await serial_asyncio.open_serial_connection(
|
||||
url=self.comport,
|
||||
baudrate=self.baudrate
|
||||
)
|
||||
|
||||
self.logger.info(f"Connected to {self.comport}")
|
||||
|
||||
data = [header.to_bytes(1, 'little'),
|
||||
int(self.controller_number, 16).to_bytes(1, 'little'),
|
||||
cell_number.to_bytes(1, 'little'),
|
||||
command.to_bytes(1, 'little')]
|
||||
|
||||
data_string = b''
|
||||
for i in data:
|
||||
data_string += i
|
||||
|
||||
checksum = self.bc_calculator.xor_bcc(data_string)
|
||||
|
||||
data_string += checksum.to_bytes(1, 'little')
|
||||
writer.write(data_string)
|
||||
return await reader.read(bytes_count)
|
||||
except Exception as error:
|
||||
raise error
|
||||
|
||||
async def open_cell(self, cell_number):
|
||||
'''открывает замок по номеру'''
|
||||
try:
|
||||
result = []
|
||||
answer = await self.send_command(cell_number=cell_number,
|
||||
command=self.default_consts[True],
|
||||
bytes_count=self.default_consts["RESPONSE_LENGHT"],
|
||||
header=self.default_consts["MANIPULATE_HEADER"])
|
||||
result.append({"CELL_NUMBER": cell_number,
|
||||
"CURRENT_STATUS": True if answer[-2] == 17 else False if answer[-2] == 0 else None,
|
||||
"FULL_ANSWER": answer})
|
||||
return result
|
||||
except Exception as error:
|
||||
self.logger.error(f"{error}")
|
||||
self.instance_error_count += 1
|
||||
return str(error)
|
||||
|
||||
def read_controller(self, cell_number : int, command=51, header=128):
|
||||
active_comport = serial.Serial(self.comport, baudrate=self.baudrate, timeout=2)
|
||||
self.logger.info(f"Connected to {active_comport.name }")
|
||||
data = [header.to_bytes(1, 'little'),
|
||||
int(self.controller_number, 16).to_bytes(1, 'little'),
|
||||
cell_number.to_bytes(1, 'little'),
|
||||
command.to_bytes(1, 'little')]
|
||||
|
||||
data_string = b''
|
||||
for i in data:
|
||||
data_string += i
|
||||
|
||||
checksum = self.bc_calculator.xor_bcc(data_string)
|
||||
|
||||
data_string += checksum.to_bytes(1, 'little')
|
||||
active_comport.write(data_string)
|
||||
return active_comport.read(5)
|
||||
|
||||
def READ_ALL_CELLS(self):
|
||||
async def READ_ALL_CELLS(self):
|
||||
'''и возвращает состояние всех замков'''
|
||||
try:
|
||||
result = []
|
||||
for i in range(0, self.controller_capacity - 1):
|
||||
answer = self.send_command(cell_number=i,
|
||||
command=self.default_consts["INFO"],
|
||||
bytes_count=self.default_consts["RESPONSE_LENGHT"],
|
||||
header=self.default_consts["READ_HEADER"])
|
||||
for i in range(1, self.controller_capacity + 1):
|
||||
answer = await self.send_command(cell_number=i,
|
||||
command=self.default_consts["INFO"],
|
||||
bytes_count=self.default_consts["RESPONSE_LENGHT"],
|
||||
header=self.default_consts["READ_HEADER"])
|
||||
result.append({"CELL_NUMBER": i,
|
||||
"CURRENT_STATUS": True if answer[-2] == 17 else False,
|
||||
"FULL_ANSWER": answer})
|
||||
"CURRENT_STATUS": True if answer[-2] == 17 else False if answer[-2] == 0 else None,
|
||||
"FULL_ANSWER": answer})
|
||||
return result
|
||||
except Exception as error:
|
||||
self.logger.error(f"{error}")
|
||||
self.instance_error_count += 1
|
||||
return str(error)
|
||||
|
||||
def OPEN_ALL_CELLS_LEGACY(self, confirm : bool):
|
||||
async def set_controller_capacity_unsafe(self, capacity: int = 0):
|
||||
'''Устанавливает количество доступных замков'''
|
||||
if capacity >= 0:
|
||||
self.controller_capacity = capacity
|
||||
# else:
|
||||
# # target max capatity
|
||||
# self.controller_capacity = 128
|
||||
# result = await self.READ_ALL_CELLS()
|
||||
# if isinstance(result, list):
|
||||
# self.controller_capacity = len(result)
|
||||
# self.logger.info(f"Controller capacity set to {self.controller_capacity}")
|
||||
# else:
|
||||
# self.logger.error("READ_ALL_CELLS() failed")
|
||||
# return False
|
||||
|
||||
async def OPEN_ALL_CELLS_LEGACY(self, confirm : bool):
|
||||
'''Открывает все замки вручную и возвращает состояние всех замков
|
||||
Confirm - подтверждение операции'''
|
||||
if confirm:
|
||||
try:
|
||||
result = []
|
||||
for i in range(1, self.controller_capacity + 1):
|
||||
answer = self.send_command(cell_number=i,
|
||||
answer = await self.send_command(cell_number=i,
|
||||
command=self.default_consts[True],
|
||||
bytes_count=self.default_consts["RESPONSE_LENGHT"],
|
||||
header=self.default_consts["MANIPULATE_HEADER"])
|
||||
result.append({"CELL_NUMBER": i,
|
||||
"CURRENT_STATUS": True if answer[-2] == 17 else False,
|
||||
"CURRENT_STATUS": True if answer[-2] == 17 else False if answer[-2] == 0 else None,
|
||||
"FULL_ANSWER": answer})
|
||||
return result
|
||||
except Exception as error:
|
||||
self.logger.error(f"{error}")
|
||||
self.instance_error_count += 1
|
||||
return str(error)
|
||||
else:
|
||||
return 1
|
||||
|
||||
def set_controller_capacity(self, capacity=0) -> str:
|
||||
async def set_controller_capacity(self, capacity=0) -> str:
|
||||
'''Устанавливает количество доступных замков'''
|
||||
if capacity != 0:
|
||||
self.controller_capacity = capacity
|
||||
return self.controller_capacity
|
||||
else:
|
||||
# тут должно быть автоматическое определение кол-ва замков на контроллере
|
||||
# try:
|
||||
# return self.send_command(0, self.default_consts[True],
|
||||
# self.default_consts["MANIPULATE_HEADER"],
|
||||
# bytes_count=self.controller_capacity)
|
||||
# except Exception as error:
|
||||
# return str(error)
|
||||
pass
|
||||
try:
|
||||
# написать
|
||||
count = await self.send_command(0, self.default_consts[True],
|
||||
self.default_consts["MANIPULATE_HEADER"],
|
||||
bytes_count=self.controller_capacity)
|
||||
except Exception as error:
|
||||
return str(error)
|
||||
|
||||
# async def create_async_connection(self):
|
||||
|
||||
# try:
|
||||
# self.async_connection = await serial_asyncio.open_serial_connection(
|
||||
# url=self.comport,
|
||||
# baudrate=self.baudrate
|
||||
# )
|
||||
# self.logger.info(f"Async connection to {self.comport}")
|
||||
# except Exception as error:
|
||||
# self.logger.error(f"Async connection error: {error}")
|
||||
# pass
|
||||
|
||||
#хочу асинхронности
|
||||
async def watchdog(self):
|
||||
'''Слушает контролер в реальном времени и возвращает bytearray с событием'''
|
||||
try:
|
||||
@@ -212,9 +236,11 @@ class caser:
|
||||
|
||||
except Exception as error:
|
||||
self.logger.error(f"{error}")
|
||||
self.instance_error_count = self.instance_error_count + 1
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
|
||||
except Exception as error:
|
||||
self.logger.critical(f"{error}")
|
||||
self.instance_error_count = self.instance_error_count + 1
|
||||
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
pyserial
|
||||
asyncpg_lite
|
||||
pyserial-asyncio
|
||||
aiogram
|
||||
23
start-tg.py
Normal file
23
start-tg.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import asyncio
|
||||
from aiogram import Router, F
|
||||
from aiogram import Bot, Dispatcher
|
||||
|
||||
import configparser
|
||||
import os
|
||||
from asyncpg_lite import DatabaseManager
|
||||
|
||||
import handlers
|
||||
|
||||
token = configparser.ConfigParser()
|
||||
token.read('temp/token.ini', encoding='utf-8-sig')
|
||||
bot = Bot(token=token.get("Main", "token"))
|
||||
handlers.init(bot)
|
||||
|
||||
async def main():
|
||||
dp = Dispatcher()
|
||||
dp.include_routers(handlers.router)
|
||||
|
||||
await dp.start_polling(bot)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -4,7 +4,6 @@ import configparser
|
||||
import serial
|
||||
import socket
|
||||
import asyncio
|
||||
import time
|
||||
|
||||
if __name__ == "__main__":
|
||||
#consts&confs
|
||||
@@ -30,20 +29,22 @@ if __name__ == "__main__":
|
||||
config=config, logger=logger)
|
||||
zxc.set_controller_number(1)
|
||||
zxc.set_port_device()
|
||||
zxc.set_controller_capacity(18)
|
||||
|
||||
# добавь *aargs
|
||||
#print(zxc.READ_ALL_CELLS())
|
||||
#print(zxc.OPEN_ALL_CELLS_LEGACY(True))
|
||||
|
||||
# print(zxc.read_controller(1))
|
||||
# print(zxc.read_controller(1))
|
||||
|
||||
async def main(zxc):
|
||||
# await zxc.set_controller_capacity(18)
|
||||
|
||||
print(await zxc.send_command(1, 17))
|
||||
exit()
|
||||
# print(await zxc.watchdog())
|
||||
# print(await zxc.OPEN_ALL_CELLS_LEGACY(True))
|
||||
#print(await zxc.READ_ALL_CELLS())
|
||||
# print(await zxc.read_controller(1))
|
||||
# print(await zxc.send_command(1, 17))
|
||||
# print(await zxc.open_cell(1))
|
||||
# print(await zxc.set_controller_capacity_unsafe(18))
|
||||
# print(await zxc.READ_ALL_CELLS())
|
||||
|
||||
pass
|
||||
|
||||
while True:
|
||||
asyncio.run(main(zxc))
|
||||
Reference in New Issue
Block a user