From f6e7dfcd93495b17aa231b7b1f148c723bcc85a1 Mon Sep 17 00:00:00 2001 From: MixBadGun <1059129006@qq.com> Date: Wed, 19 Nov 2025 16:24:24 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A9=BA=E8=B0=83=E6=9C=80=E9=AB=98=E5=B3=B0?= =?UTF-8?q?=EF=BC=8C=E7=A9=BA=E8=B0=83=E6=95=B0=E6=8D=AE=E5=BA=93=E6=8C=82?= =?UTF-8?q?=E8=BD=BD=E5=86=8D=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- konabot/plugins/air_conditioner/__init__.py | 66 +++++++++++++------ konabot/plugins/air_conditioner/ac.py | 40 +++++++---- .../air_conditioner/sql/create_table.sql | 11 ++++ .../plugins/air_conditioner/sql/insert_ac.sql | 7 +- .../plugins/air_conditioner/sql/query_ac.sql | 2 +- .../air_conditioner/sql/query_peak.sql | 13 ++++ .../plugins/air_conditioner/sql/update_ac.sql | 6 ++ 7 files changed, 111 insertions(+), 34 deletions(-) create mode 100644 konabot/plugins/air_conditioner/sql/query_peak.sql diff --git a/konabot/plugins/air_conditioner/__init__.py b/konabot/plugins/air_conditioner/__init__.py index 27b88e6..db12c48 100644 --- a/konabot/plugins/air_conditioner/__init__.py +++ b/konabot/plugins/air_conditioner/__init__.py @@ -117,22 +117,18 @@ async def _(target: DepLongTaskTarget, temp: Optional[Union[int, float]] = 1): await send_ac_image(evt, ac) return await ac.update_ac(temperature_delta=temp) - if ac.temperature > 40: - # 根据温度随机出是否爆炸,40度开始,呈指数增长 - possibility = -math.e ** ((40-ac.temperature) / 50) + 1 - if random.random() < possibility: - # 打开爆炸图片 - with open(ASSETS_PATH / "img" / "other" / "boom.jpg", "rb") as f: - output = BytesIO() - # 爆炸抖动 - frames = wiggle_transform(np.array(Image.open(f)), intensity=5) - pil_frames = [Image.fromarray(frame) for frame in frames] - pil_frames[0].save(output, format="GIF", save_all=True, append_images=pil_frames[1:], loop=0, duration=35, disposal=2) - output.seek(0) - await evt.send(await UniMessage().image(raw=output).export()) - await ac.broke_ac(CrashType.BURNT) - await evt.send("太热啦,空调炸了!") - return + if ac.burnt: + # 打开爆炸图片 + with open(ASSETS_PATH / "img" / "other" / "boom.jpg", "rb") as f: + output = BytesIO() + # 爆炸抖动 + frames = wiggle_transform(np.array(Image.open(f)), intensity=5) + pil_frames = [Image.fromarray(frame) for frame in frames] + pil_frames[0].save(output, format="GIF", save_all=True, append_images=pil_frames[1:], loop=0, duration=35, disposal=2) + output.seek(0) + await evt.send(await UniMessage().image(raw=output).export()) + await evt.send("太热啦,空调炸了!") + return await send_ac_image(evt, ac) evt = on_alconna(Alconna( @@ -152,11 +148,6 @@ async def _(target: DepLongTaskTarget, temp: Optional[Union[int, float]] = 1): await send_ac_image(evt, ac) return await ac.update_ac(temperature_delta=-temp) - if ac.temperature < 0: - # 根据温度随机出是否冻结,0度开始,呈指数增长 - possibility = -math.e ** (ac.temperature / 50) + 1 - if random.random() < possibility: - await ac.broke_ac(CrashType.FROZEN) await send_ac_image(evt, ac) evt = on_alconna(Alconna( @@ -202,3 +193,36 @@ async def _(target: DepLongTaskTarget): params=params ) await evt.send(await UniMessage().image(raw=image).export()) + +evt = on_alconna(Alconna( + "空调最高峰", +), use_cmd_start=True, use_cmd_sep=False, skip_for_unmatch=True) + +@evt.handle() +async def _(target: DepLongTaskTarget): + result = await db_manager.query_by_sql_file( + ROOT_PATH / "sql" / "query_peak.sql" + ) + if len(result) == 0: + await evt.send("没有空调记录!") + return + max_temp = result[0].get("max") + min_temp = result[0].get("min") + his_max = result[0].get("his_max") + his_min = result[0].get("his_min") + # 再从内存里的空调池中获取最高温度和最低温度 + for ac in AirConditioner.InstancesPool.values(): + if ac.on and not ac.burnt and not ac.frozen: + if max_temp is None or min_temp is None: + max_temp = ac.temperature + min_temp = ac.temperature + max_temp = max(max_temp, ac.temperature) + min_temp = min(min_temp, ac.temperature) + if max_temp is None or min_temp is None: + await evt.send(f"目前全部空调都被炸掉了!") + else: + await evt.send(f"全球在线空调最高温度为 {'%.1f' % max_temp}°C,最低温度为 {'%.1f' % min_temp}°C!") + if his_max is None or his_min is None: + pass + else: + await evt.send(f"历史最高温度为 {'%.1f' % his_max}°C,最低温度为 {'%.1f' % his_min}°C!\n(要进入历史记录,温度需至少保持 5 分钟)") \ No newline at end of file diff --git a/konabot/plugins/air_conditioner/ac.py b/konabot/plugins/air_conditioner/ac.py index 83d0297..7413614 100644 --- a/konabot/plugins/air_conditioner/ac.py +++ b/konabot/plugins/air_conditioner/ac.py @@ -1,7 +1,9 @@ import asyncio from enum import Enum from io import BytesIO +import math from pathlib import Path +import random import signal import time @@ -28,13 +30,8 @@ class CrashType(Enum): driver = nonebot.get_driver() -ac_manager: 'AirConditionerManager' = None - @driver.on_startup async def register_startup_hook(): - global ac_manager - # 启动自动保存任务 - ac_manager = AirConditionerManager(save_interval=300) # 5分钟 await ac_manager.start_auto_save() @driver.on_shutdown @@ -89,10 +86,10 @@ class AirConditionerManager: try: await db_manager.execute_by_sql_file( ROOT_PATH / "sql" / "update_ac.sql", - (ac_instance.on, ac_instance.temperature, - ac_instance.burnt, ac_instance.frozen, ac_id) + [(ac_instance.on, ac_instance.temperature, + ac_instance.burnt, ac_instance.frozen, ac_id),(ac_id,)] ) - if(save_time - ac_instance.instance_get_time >= 3600): + if(save_time - ac_instance.instance_get_time >= 300): # 5 分钟 to_remove.append(ac_id) except Exception as e: logger.error(f"保存空调 {ac_id} 失败: {e}") @@ -105,6 +102,8 @@ class AirConditionerManager: logger.info(f"清理长期不活跃的空调实例完成,目前池内共有 {len(AirConditioner.InstancesPool)} 个实例") +ac_manager = AirConditionerManager(save_interval=300) # 5分钟 + class AirConditioner: InstancesPool: dict[str, 'AirConditioner'] = {} @@ -119,7 +118,7 @@ class AirConditioner: @classmethod async def get_ac(cls, id: str) -> 'AirConditioner': if(id in cls.InstancesPool): - cls.refresh_ac(id) + await cls.refresh_ac(id) return cls.InstancesPool[id] # 如果没有,那么从数据库重新实例化一个 AC 出来 result = await db_manager.query_by_sql_file(ROOT_PATH / "sql" / "query_ac.sql", (id,)) @@ -140,16 +139,35 @@ class AirConditioner: ac = AirConditioner(id) await db_manager.execute_by_sql_file( ROOT_PATH / "sql" / "insert_ac.sql", - (id, ac.on, ac.temperature, ac.burnt, ac.frozen) + [(id, ac.on, ac.temperature, ac.burnt, ac.frozen),(id,)] ) await cls.storage_ac(id, ac) return ac + async def change_ac_temp(self, temperature_delta: float) -> None: + ''' + 改变空调的温度 + :param temperature_delta: float 温度变化量 + ''' + changed_temp = self.temperature + temperature_delta + random_poss = random.random() + if temperature_delta < 0 and changed_temp < 0: + # 根据温度随机出是否冻结,0度开始,呈指数增长 + possibility = -math.e ** (changed_temp / 50) + 1 + if random_poss < possibility: + await self.broke_ac(CrashType.FROZEN) + elif temperature_delta > 0 and changed_temp > 40: + # 根据温度随机出是否烧坏,40度开始,呈指数增长 + possibility = -math.e ** ((40-changed_temp) / 50) + 1 + if random_poss < possibility: + await self.broke_ac(CrashType.BURNT) + self.temperature = changed_temp + async def update_ac(self, state: bool = None, temperature_delta: float = None, burnt: bool = None, frozen: bool = None) -> 'AirConditioner': if state is not None: self.on = state if temperature_delta is not None: - self.temperature += temperature_delta + await self.change_ac_temp(temperature_delta) if burnt is not None: self.burnt = burnt if frozen is not None: diff --git a/konabot/plugins/air_conditioner/sql/create_table.sql b/konabot/plugins/air_conditioner/sql/create_table.sql index fed346c..b7e225e 100644 --- a/konabot/plugins/air_conditioner/sql/create_table.sql +++ b/konabot/plugins/air_conditioner/sql/create_table.sql @@ -7,6 +7,17 @@ CREATE TABLE IF NOT EXISTS air_conditioner ( frozen BOOLEAN NOT NULL ); +CREATE TABLE IF NOT EXISTS air_conditioner_log ( + log_id INTEGER PRIMARY KEY AUTOINCREMENT, + log_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + id VARCHAR(128), + "on" BOOLEAN NOT NULL, + temperature REAL NOT NULL, + burnt BOOLEAN NOT NULL, + frozen BOOLEAN NOT NULL, + FOREIGN KEY (id) REFERENCES air_conditioner(id) +); + CREATE TABLE IF NOT EXISTS air_conditioner_crash_log ( id VARCHAR(128) NOT NULL, crash_type INT NOT NULL, diff --git a/konabot/plugins/air_conditioner/sql/insert_ac.sql b/konabot/plugins/air_conditioner/sql/insert_ac.sql index 96e80ac..8d811c6 100644 --- a/konabot/plugins/air_conditioner/sql/insert_ac.sql +++ b/konabot/plugins/air_conditioner/sql/insert_ac.sql @@ -1,3 +1,8 @@ -- 插入一台新空调 INSERT INTO air_conditioner (id, "on", temperature, burnt, frozen) -VALUES (?, ?, ?, ?, ?); \ No newline at end of file +VALUES (?, ?, ?, ?, ?); +-- 使用返回的数据插入日志 +INSERT INTO air_conditioner_log (id, "on", temperature, burnt, frozen) +SELECT id, "on", temperature, burnt, frozen +FROM air_conditioner +WHERE id = ?; \ No newline at end of file diff --git a/konabot/plugins/air_conditioner/sql/query_ac.sql b/konabot/plugins/air_conditioner/sql/query_ac.sql index db957d3..9dddc62 100644 --- a/konabot/plugins/air_conditioner/sql/query_ac.sql +++ b/konabot/plugins/air_conditioner/sql/query_ac.sql @@ -1,4 +1,4 @@ --- 查询空调状态,如果没有就插入一条新的记录 +-- 查询空调状态 SELECT * FROM air_conditioner WHERE id = ?; \ No newline at end of file diff --git a/konabot/plugins/air_conditioner/sql/query_peak.sql b/konabot/plugins/air_conditioner/sql/query_peak.sql new file mode 100644 index 0000000..9288e8e --- /dev/null +++ b/konabot/plugins/air_conditioner/sql/query_peak.sql @@ -0,0 +1,13 @@ +-- 查询目前所有空调中的最高温度与最低温度与历史最高低温 +SELECT + (SELECT MAX(temperature) FROM air_conditioner + WHERE "on" = TRUE AND NOT frozen AND NOT burnt) AS max, + + (SELECT MIN(temperature) FROM air_conditioner + WHERE "on" = TRUE AND NOT frozen AND NOT burnt) AS min, + + (SELECT MAX(temperature) FROM air_conditioner_log + WHERE "on" = TRUE AND NOT frozen AND NOT burnt) AS his_max, + + (SELECT MIN(temperature) FROM air_conditioner_log + WHERE "on" = TRUE AND NOT frozen AND NOT burnt) AS his_min; \ No newline at end of file diff --git a/konabot/plugins/air_conditioner/sql/update_ac.sql b/konabot/plugins/air_conditioner/sql/update_ac.sql index 474d71b..9f7a9d5 100644 --- a/konabot/plugins/air_conditioner/sql/update_ac.sql +++ b/konabot/plugins/air_conditioner/sql/update_ac.sql @@ -1,4 +1,10 @@ -- 更新空调状态 UPDATE air_conditioner SET "on" = ?, temperature = ?, burnt = ?, frozen = ? +WHERE id = ?; + +-- 插入日志记录(从更新后的数据获取) +INSERT INTO air_conditioner_log (id, "on", temperature, burnt, frozen) +SELECT id, "on", temperature, burnt, frozen +FROM air_conditioner WHERE id = ?; \ No newline at end of file