202 lines
6.6 KiB
Python
202 lines
6.6 KiB
Python
from nonebot_plugin_apscheduler import scheduler
|
|
import nonebot
|
|
from nonebot import on_command
|
|
from nonebot.rule import Rule
|
|
from nonebot.adapters.onebot.v11.adapter import Message, MessageSegment
|
|
from nonebot.adapters.onebot.v11 import Message, MessageSegment, Bot, MessageEvent
|
|
from nonebot.matcher import Matcher
|
|
from nonebot.params import CommandArg
|
|
import aiohttp
|
|
import json
|
|
import re
|
|
import asyncio
|
|
from pathlib import Path
|
|
|
|
from .config import Config
|
|
from .data import load_binding_data, BUILDING_TAB, HELP, get_bid_by_bname
|
|
|
|
|
|
electricity_check = on_command(
|
|
'eleccheck', rule=Rule(), aliases={'查电费'}, priority=5)
|
|
|
|
elec_check_config = Config.parse_obj(nonebot.get_driver().config.dict())
|
|
|
|
data_path = Path().absolute() / "data" / "eleccheck"
|
|
|
|
REQ_DATA = {"query_elec_roominfo": {"aid": "0030000000002501", "account": "251277", "room": {"roomid": "", "room": ""}, "floor": {
|
|
"floorid": "", "floor": ""}, "area": {"area": "云塘校区", "areaname": "云塘校区"}, "building": {"buildingid": "451", "building": "17栋"}}}
|
|
API = 'http://yktwd.csust.edu.cn:8988/web/Common/Tsm.html'
|
|
HEADERS = {
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.50',
|
|
'Referer': 'http://yktwd.csust.edu.cn:8988/web/common/checkEle.html?ticket=2E94FD6F19FB40558D53CC55AE4421E4&from=ehall&cometype=',
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
}
|
|
RESULT_PATTERN = r'房间剩余电量([\d\.]+)'
|
|
re_result = re.compile(RESULT_PATTERN)
|
|
|
|
bindings = load_binding_data(str(data_path / 'bindings.json'))
|
|
|
|
|
|
async def reload_bindings():
|
|
global bindings
|
|
bindings = load_binding_data(str(data_path / 'bindings.json'))
|
|
|
|
|
|
async def batch_check():
|
|
"""批量检测低电量房间并推送到群聊
|
|
"""
|
|
bot = nonebot.get_bot()
|
|
if not bindings:
|
|
return
|
|
|
|
for binding_info in bindings:
|
|
group = binding_info['group']
|
|
rooms = binding_info['rooms']
|
|
default_building = binding_info['building']
|
|
result = []
|
|
for r in rooms:
|
|
rid = r['roomid']
|
|
bname = r.get('building', default_building)
|
|
bid = get_bid_by_bname(bname)
|
|
try:
|
|
remain = await get_electricity(building_id=bid, building_name=bname, roomid=rid)
|
|
except Exception as e:
|
|
print('获取信息出错:' + str(e))
|
|
result.append({'roomid': rid, 'remain': remain, 'building': bname})
|
|
await asyncio.sleep(0.5)
|
|
|
|
msg = ['电量不足预警:\n']
|
|
for res in result:
|
|
elec = float(res['remain'])
|
|
if elec <= 50:
|
|
msg.append('\n{}{}剩余电量:{}'.format(
|
|
res['building'], res['roomid'], res['remain']))
|
|
if len(msg) > 1:
|
|
await bot.send_group_msg(group_id=group, message=Message(msg))
|
|
|
|
if bindings:
|
|
scheduler.add_job(
|
|
batch_check,
|
|
'cron',
|
|
hour=15,
|
|
minute=0,
|
|
second=0,
|
|
id='batch_elec_check_and_push'
|
|
)
|
|
|
|
|
|
async def get_electricity(building_id: str, building_name: str, roomid: str) -> str:
|
|
"""通过API获取电量信息
|
|
|
|
Args:
|
|
building_id (str):
|
|
building_name (str):
|
|
roomid (str):
|
|
|
|
Raises:
|
|
IOError:
|
|
RuntimeError:
|
|
|
|
Returns:
|
|
str:
|
|
"""
|
|
# 组织参数
|
|
jsondata = REQ_DATA.copy()
|
|
jsondata['query_elec_roominfo']['room']['roomid'] = roomid
|
|
jsondata['query_elec_roominfo']['room']['room'] = roomid
|
|
jsondata['query_elec_roominfo']['building']['buildingid'] = building_id
|
|
jsondata['query_elec_roominfo']['building']['building'] = building_name
|
|
payload = {
|
|
"jsondata": json.dumps(jsondata),
|
|
"funname": "synjones.onecard.query.elec.roominfo",
|
|
"json": True
|
|
}
|
|
|
|
# 查询请求
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.post(url=API, data=payload, headers=HEADERS) as res:
|
|
if res.status != 200:
|
|
raise IOError('接口调用失败: Code ' + res.status)
|
|
res_raw = await res.text()
|
|
|
|
try:
|
|
res_json = json.loads(res_raw)
|
|
except json.decoder.JSONDecodeError:
|
|
raise IOError('接口调用失败: ' + res_raw)
|
|
|
|
if res_json['query_elec_roominfo']['retcode'] != '0':
|
|
raise RuntimeError(
|
|
'获取失败: ' + res_json['query_elec_roominfo']['errmsg'])
|
|
|
|
msg = res_json['query_elec_roominfo']['errmsg'].strip()
|
|
# 检查返回结果是否合法,并抽取电量数值
|
|
match = re_result.match(msg)
|
|
if not match:
|
|
raise RuntimeError(
|
|
'获取失败: ' + res_json['query_elec_roominfo']['errmsg'])
|
|
|
|
elec_quantity = re_result.findall(msg)[0]
|
|
return elec_quantity
|
|
|
|
|
|
async def building_list() -> list[str]:
|
|
"""获取所有楼栋名列表
|
|
|
|
Returns:
|
|
list[str]: 楼栋名列表
|
|
"""
|
|
buildings = []
|
|
for b in BUILDING_TAB:
|
|
buildings.append(b['building'])
|
|
return buildings
|
|
|
|
|
|
@electricity_check.handle()
|
|
async def elec_check_handler(matcher: Matcher, event: MessageEvent, arg: Message = CommandArg()):
|
|
if event.message_type != 'group':
|
|
await matcher.finish()
|
|
|
|
group = event.group_id
|
|
# 白名单检查
|
|
if str(group) not in elec_check_config.elec_check_enable:
|
|
await matcher.finish()
|
|
|
|
# 参数检查
|
|
args = arg.extract_plain_text()
|
|
if len(args) == 0:
|
|
await matcher.finish(HELP)
|
|
args = args.rsplit()
|
|
|
|
if args[0] == '楼栋列表':
|
|
buildings = await building_list()
|
|
msg = '支持的所有楼栋名:\n' + '\n'.join(buildings)
|
|
await matcher.finish(msg)
|
|
if args[0] == '自动预警配置查询':
|
|
await matcher.finish('该功能尚未开放')
|
|
if args[0] == '重载':
|
|
# TODO: 管理员权限检测
|
|
await reload_bindings()
|
|
await matcher.finish('插件配置已重载')
|
|
if args[0] == '推送':
|
|
# TODO: 管理员权限检测
|
|
await batch_check()
|
|
await matcher.finish('已推送所有预警')
|
|
|
|
if len(args) < 2:
|
|
await matcher.finish(HELP)
|
|
|
|
building_name = args[0]
|
|
roomid = args[1]
|
|
building_id = get_bid_by_bname(building_name)
|
|
if not building_id:
|
|
await matcher.finish('参数错误:楼栋名不存在')
|
|
|
|
try:
|
|
electricity = await get_electricity(building_id=building_id,
|
|
building_name=building_name,
|
|
roomid=roomid)
|
|
except Exception as e:
|
|
await matcher.finish(str(e))
|
|
|
|
await matcher.finish('{}{}剩余电量:{}'.format(building_name, roomid, electricity))
|