160 lines
4.7 KiB
Python
160 lines
4.7 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
Redis 模拟数据填充工具
|
|||
|
|
- 从数据库读取前10个设备
|
|||
|
|
- 生成随机状态写入Redis(设备级+板级+通道级)
|
|||
|
|
- 300秒后自动过期(与设备上报TTL一致)
|
|||
|
|
|
|||
|
|
用法:
|
|||
|
|
python tools/mock_redis.py # 填充模拟数据
|
|||
|
|
python tools/mock_redis.py --clear # 清除所有模拟数据
|
|||
|
|
"""
|
|||
|
|
import sys
|
|||
|
|
import json
|
|||
|
|
import random
|
|||
|
|
import redis
|
|||
|
|
import pymysql
|
|||
|
|
|
|||
|
|
# Redis 配置
|
|||
|
|
REDIS_HOST = "10.8.0.252"
|
|||
|
|
REDIS_PORT = 6379
|
|||
|
|
REDIS_PASSWORD = "Hbhyg731024@"
|
|||
|
|
REDIS_DB = 5
|
|||
|
|
|
|||
|
|
# MySQL 配置
|
|||
|
|
MYSQL_HOST = "10.8.0.252"
|
|||
|
|
MYSQL_PORT = 3306
|
|||
|
|
MYSQL_USER = "root"
|
|||
|
|
MYSQL_PASSWORD = "Hbhyg731024@"
|
|||
|
|
MYSQL_DB = "pms"
|
|||
|
|
|
|||
|
|
# 设备数量
|
|||
|
|
DEVICE_COUNT = 10
|
|||
|
|
|
|||
|
|
# 通道状态: 0=空闲, 1=插入, 2=充电中, 3=充满, 4=故障
|
|||
|
|
STATUS_IDLE = 0
|
|||
|
|
STATUS_INSERTED = 1
|
|||
|
|
STATUS_CHARGING = 2
|
|||
|
|
STATUS_FULL = 3
|
|||
|
|
STATUS_FAULT = 4
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_devices():
|
|||
|
|
"""从数据库获取前N个设备"""
|
|||
|
|
conn = pymysql.connect(
|
|||
|
|
host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER,
|
|||
|
|
password=MYSQL_PASSWORD, database=MYSQL_DB, charset="utf8mb4"
|
|||
|
|
)
|
|||
|
|
try:
|
|||
|
|
with conn.cursor(pymysql.cursors.DictCursor) as cur:
|
|||
|
|
cur.execute("""
|
|||
|
|
SELECT c.imei, c.abstract_id, c.name,
|
|||
|
|
(SELECT COUNT(*) FROM cabin_boards cb WHERE cb.cabinet_id = c.id) as board_count
|
|||
|
|
FROM cabinets c ORDER BY c.id LIMIT %s
|
|||
|
|
""", (DEVICE_COUNT,))
|
|||
|
|
return cur.fetchall()
|
|||
|
|
finally:
|
|||
|
|
conn.close()
|
|||
|
|
|
|||
|
|
|
|||
|
|
def gen_channel_hex(status: int) -> str:
|
|||
|
|
"""生成单通道hex(4字节=8个hex字符)"""
|
|||
|
|
# 字节1: bit0=在线 bit1=充电中 bit2=充满 bit3=故障
|
|||
|
|
byte1 = 0x01 # 在线
|
|||
|
|
if status == STATUS_CHARGING:
|
|||
|
|
byte1 |= 0x02
|
|||
|
|
elif status == STATUS_FULL:
|
|||
|
|
byte1 |= 0x04
|
|||
|
|
elif status == STATUS_FAULT:
|
|||
|
|
byte1 |= 0x08
|
|||
|
|
# 字节2-4: 随机(模拟电压电流等)
|
|||
|
|
byte2 = random.randint(0x10, 0x60)
|
|||
|
|
byte3 = random.randint(0x00, 0xFF)
|
|||
|
|
byte4 = random.randint(0x00, 0xFF)
|
|||
|
|
return f"{byte1:02x}{byte2:02x}{byte3:02x}{byte4:02x}"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def gen_board_status_hex(board_idx: int) -> str:
|
|||
|
|
"""生成一块板6个通道的status_hex"""
|
|||
|
|
parts = []
|
|||
|
|
for ch in range(6):
|
|||
|
|
# 随机分配状态,充电和故障少一些
|
|||
|
|
r = random.random()
|
|||
|
|
if r < 0.02:
|
|||
|
|
status = STATUS_FAULT
|
|||
|
|
elif r < 0.25:
|
|||
|
|
status = STATUS_CHARGING
|
|||
|
|
elif r < 0.32:
|
|||
|
|
status = STATUS_FULL
|
|||
|
|
elif r < 0.42:
|
|||
|
|
status = STATUS_INSERTED
|
|||
|
|
else:
|
|||
|
|
status = STATUS_IDLE
|
|||
|
|
parts.append(gen_channel_hex(status))
|
|||
|
|
return "".join(parts)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def fill_mock_data():
|
|||
|
|
"""填充模拟数据"""
|
|||
|
|
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, db=REDIS_DB, decode_responses=True)
|
|||
|
|
devices = get_devices()
|
|||
|
|
print(f"获取到 {len(devices)} 个设备")
|
|||
|
|
|
|||
|
|
for dev in devices:
|
|||
|
|
imei = dev["imei"]
|
|||
|
|
board_count = dev.get("board_count") or 6
|
|||
|
|
device_key = f"device:{imei}"
|
|||
|
|
|
|||
|
|
# 设备级
|
|||
|
|
r.hset(device_key, mapping={
|
|||
|
|
"online": "1",
|
|||
|
|
"rssi": str(random.randint(30, 95)),
|
|||
|
|
"pow_fail_dc": random.choice(["0", "0", "0", "1"]), # 25%概率停电
|
|||
|
|
"pow_fail_ac": "0",
|
|||
|
|
})
|
|||
|
|
r.expire(device_key, 300)
|
|||
|
|
|
|||
|
|
# 板级 + 通道级
|
|||
|
|
for board_idx in range(1, board_count + 1):
|
|||
|
|
board_key = f"{device_key}:board:{board_idx}"
|
|||
|
|
status_hex = gen_board_status_hex(board_idx)
|
|||
|
|
r.hset(board_key, mapping={"status_hex": status_hex})
|
|||
|
|
|
|||
|
|
# 解析6个通道
|
|||
|
|
for ch in range(6):
|
|||
|
|
ch_hex = status_hex[ch * 8 : (ch + 1) * 8]
|
|||
|
|
byte1 = int(ch_hex[0:2], 16)
|
|||
|
|
ch_key = f"{board_key}:ch:{ch}"
|
|||
|
|
r.hset(ch_key, mapping={
|
|||
|
|
"on": "1" if byte1 & 0x02 else "0",
|
|||
|
|
"full": "1" if byte1 & 0x04 else "0",
|
|||
|
|
"fault": "1" if byte1 & 0x08 else "0",
|
|||
|
|
"hex": ch_hex,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
name = dev.get("name") or imei
|
|||
|
|
print(f" ✓ {name} ({imei}) — {board_count}板")
|
|||
|
|
|
|||
|
|
print(f"\n完成!已填充 {len(devices)} 个设备,300秒后自动过期")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def clear_mock_data():
|
|||
|
|
"""清除所有模拟数据"""
|
|||
|
|
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, db=REDIS_DB, decode_responses=True)
|
|||
|
|
devices = get_devices()
|
|||
|
|
count = 0
|
|||
|
|
for dev in devices:
|
|||
|
|
imei = dev["imei"]
|
|||
|
|
keys = r.keys(f"device:{imei}*")
|
|||
|
|
if keys:
|
|||
|
|
r.delete(*keys)
|
|||
|
|
count += len(keys)
|
|||
|
|
print(f"已清除 {count} 个 Redis key")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
if "--clear" in sys.argv:
|
|||
|
|
clear_mock_data()
|
|||
|
|
else:
|
|||
|
|
fill_mock_data()
|