✨查电费基础功能完成,支持简单推送
This commit is contained in:
parent
c07df37bb7
commit
db5123f259
|
@ -0,0 +1,201 @@
|
|||
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))
|
|
@ -0,0 +1,6 @@
|
|||
from typing import List
|
||||
from pydantic import BaseModel, Extra
|
||||
|
||||
|
||||
class Config(BaseModel, extra=Extra.ignore):
|
||||
elec_check_enable: List = []
|
|
@ -0,0 +1,185 @@
|
|||
import json
|
||||
|
||||
BUILDING_TAB = [{
|
||||
"buildingid": "471",
|
||||
"building": "16栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "472",
|
||||
"building": "16栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "451",
|
||||
"building": "17栋"
|
||||
},
|
||||
{
|
||||
"buildingid": "141",
|
||||
"building": "弘毅轩1栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "148",
|
||||
"building": "弘毅轩1栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "197",
|
||||
"building": "弘毅轩2栋A区1-6楼"
|
||||
},
|
||||
{
|
||||
"buildingid": "201",
|
||||
"building": "弘毅轩2栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "205",
|
||||
"building": "弘毅轩2栋C区"
|
||||
},
|
||||
{
|
||||
"buildingid": "206",
|
||||
"building": "弘毅轩2栋D区"
|
||||
},
|
||||
{
|
||||
"buildingid": "155",
|
||||
"building": "弘毅轩3栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "183",
|
||||
"building": "弘毅轩3栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "162",
|
||||
"building": "弘毅轩4栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "169",
|
||||
"building": "弘毅轩4栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "450",
|
||||
"building": "留学生公寓"
|
||||
},
|
||||
{
|
||||
"buildingid": "176",
|
||||
"building": "敏行轩1栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "184",
|
||||
"building": "敏行轩1栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "513",
|
||||
"building": "敏行轩2栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "520",
|
||||
"building": "敏行轩2栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "85",
|
||||
"building": "行健轩1栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "92",
|
||||
"building": "行健轩1栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "99",
|
||||
"building": "行健轩2栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "106",
|
||||
"building": "行健轩2栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "113",
|
||||
"building": "行健轩3栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "120",
|
||||
"building": "行健轩3栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "127",
|
||||
"building": "行健轩4栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "134",
|
||||
"building": "行健轩4栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "57",
|
||||
"building": "行健轩5栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "64",
|
||||
"building": "行健轩5栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "71",
|
||||
"building": "行健轩6栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "78",
|
||||
"building": "行健轩6栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "1",
|
||||
"building": "至诚轩1栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "8",
|
||||
"building": "至诚轩1栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "15",
|
||||
"building": "至诚轩2栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "22",
|
||||
"building": "至诚轩2栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "29",
|
||||
"building": "至诚轩3栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "36",
|
||||
"building": "至诚轩3栋B区"
|
||||
},
|
||||
{
|
||||
"buildingid": "43",
|
||||
"building": "至诚轩4栋A区"
|
||||
},
|
||||
{
|
||||
"buildingid": "50",
|
||||
"building": "至诚轩4栋B区"
|
||||
}]
|
||||
|
||||
building_names = dict()
|
||||
|
||||
for b in BUILDING_TAB:
|
||||
building_names[b['building']] = b['buildingid']
|
||||
|
||||
HELP = """电费查询&预警插件
|
||||
可以手动查询电费,低电量余额时自动提醒(需要管理员设置)
|
||||
|
||||
用法:
|
||||
/查电费 <命令/楼栋名> [宿舍号]
|
||||
|
||||
例:
|
||||
/查电费 17栋 406
|
||||
/查电费 16栋A区 A201
|
||||
|
||||
可用命令:
|
||||
楼栋列表 - 列出所有可使用的楼栋名
|
||||
自动预警配置查询 - N/A
|
||||
重载 - 重载插件配置文件(管理员)
|
||||
推送 - 手动推送所有预警信息(管理员)"""
|
||||
|
||||
def load_binding_data(data_path: str) -> list[dict[str, str]]:
|
||||
try:
|
||||
with open(data_path, 'r', encoding='utf-8') as fp:
|
||||
return json.load(fp)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_bid_by_bname(name: str) -> str:
|
||||
return building_names.get(name, '')
|
Loading…
Reference in New Issue