就是简单Mark一下,最近电费感觉略微有点异常,于是写了各监控看看电量情况。

对于电费啥水平,看两天我再回来写写。

电量获取

你OUC电量有这么个网页:http://10.128.13.25/expensesManager/feeManager/searchPower.jsp

上面的电量更新比较及时,比海大e卡通上面的及时。

通过抓包,可以发现接口http://10.128.13.25/feemanager/findSurplusElectricByMeterSearchPower.action

进行POST请求,再携带上我们的电费id即可,这里写了一段代码用来获取,由于有时候获取会失败,加了5次重试。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests

def get_df(code):
    url = "http://10.128.13.25/feemanager/findSurplusElectricByMeterSearchPower.action"
    i = 0
    while i < 5:
        response = requests.request(
            "POST", url, data={"equipmentInfoId": "10.150.132.63#" + code}
        ).json()
        i += 1
        print(response)
        if response.get('equipmentList'):
            break
    equipmentList = response['equipmentList']
    return {
        # 充值电量
        'surplus': float(equipmentList['roomSurplusBuyElecNum']),
        # 赠送电量
        'give': float(equipmentList['roomSurplusGiveElecNum']),
        # 总电量
        'total': float(equipmentList['roomSurplusBuyElecNum']) + float(equipmentList['roomSurplusGiveElecNum']),
        # 按当前电压
        'voltage': equipmentList['line1Voltage'],
        # 当前电流
        'electricity': equipmentList['line1Electricity'],
    }

记录数据到数据库

光获取还不行,那肯定得把数据写入数据库吧,选择MyQql数据库,于是找了一个简单的ORM框架peewee,u1s1还确实挺好用的。

没有啥特殊的,记个电量,记个时间就行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from peewee import *
import datetime

db = MySQLDatabase('dianfei', host="localhost", user='root', passwd='123456', port=3306)

class ChaZuo(Model):
    charge = DecimalField()
    time = DateTimeField()

    class Meta:
        database = db
        

class KongTiao(Model):
    charge = DecimalField()
    time = DateTimeField()

    class Meta:
        database = db

# 插座
response = get_df('')
print('插座:  ', response)
ChaZuo.create(charge=response['total'], time=datetime.datetime.now())

# 插座
response = get_df('')
print('空调:  ',response)
KongTiao.create(charge=response['total'], time=datetime.datetime.now())

然后看自己情况,每隔一段时间跑一下脚本就行,我10分钟跑一次。写个cron就是

1
*/10 * * * * python dianfei.py

可视化

本来想着做个前后端分离,或者直接拿一个Web框架模板渲染得了,等等,又得写前端,nonono。

这玩意我就图一乐,写那么多代码干嘛,于是搜搜有没有什么现成的低代码Web框架,然后搜到了Streamlit,总体感觉还行,就是手机端交互有点差,凑活着用吧。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import streamlit as st
import pandas as pd
import altair as alt
from peewee import MySQLDatabase, Model, DecimalField, DateTimeField
from playhouse.shortcuts import model_to_dict

# 连接到 MySQL 数据库
db = MySQLDatabase('dianfei', host="192.168.1.190", user='root', passwd='123456', port=3306)

# 定义模型
class ChaZuo(Model):
    charge = DecimalField()
    time = DateTimeField()

    class Meta:
        database = db

class KongTiao(Model):
    charge = DecimalField()
    time = DateTimeField()

    class Meta:
        database = db

# 查询数据
def get_data(model):
    query = model.select()
    data = pd.DataFrame(list(map(model_to_dict, query)))
    data['time'] = pd.to_datetime(data['time'])  # 确保时间字段是 datetime 类型
    return data

def web(title='插座', model=ChaZuo):
    # 获取数据并转换为 DataFrame
    data = get_data(model)

    # 确保时间列是索引
    data.set_index('time', inplace=True)

    st.markdown(f"### {title}耗电")

    # 选择时间间隔,并设置默认值为 "10分钟"
    time_interval = st.selectbox(
        "选择时间间隔", 
        ["10分钟", "半小时", "小时", "天"],
        index=0,  # index=0 表示默认选中第一个选项,即 "10分钟"
        key=title
    )

    # 根据选择的时间间隔调整数据
    if time_interval == "10分钟":
        resampled_data = data.resample("10T").last()
    elif time_interval == "半小时":
        resampled_data = data.resample("30T").last()
    elif time_interval == "天":
        resampled_data = data.resample("D").last()
    else:  # 默认为小时
        resampled_data = data.resample("H").last()

    # 计算电量的变化值,并取绝对值
    resampled_data['charge_diff'] = resampled_data['charge'].diff().fillna(resampled_data['charge']).abs()

    resampled_data['charge_diff'] = resampled_data['charge_diff'].astype(float)

    # 重置索引
    resampled_data = resampled_data.reset_index()

    x_format = "%m-%d %H:%M"

    # 绘制折线图
    line_chart = alt.Chart(resampled_data[1:]).mark_line(point=True).encode(
        x=alt.X("time:T",timeUnit='monthdatehoursminutes', axis=alt.Axis(format=x_format), title="时间"),  # 添加 title 属性
        y=alt.Y("charge_diff:Q", axis=alt.Axis(format=".3f"), title="使用电费"),  # 添加 axis 属性
        tooltip=[alt.Tooltip("time:T",timeUnit='monthdatehoursminutes', title="时间", format=x_format), 
                alt.Tooltip("charge_diff:Q", format=".3f", title="使用电费")]
    ).interactive()
    
    st.altair_chart(line_chart, use_container_width=True)

web('插座', ChaZuo)
web('空调', KongTiao)

直接运行一个streamlit run dianfei_web.py就跑起来了,访问localhost:8501就可以看到结果了。

image.png

还凑活吧,代码都是ai写的,确实比我自己写前端快。

不过也学到不少,pandas确实强大,diff和resample用的恰到好处,要我自己写的话,估计得捣鼓一阵子了,还是得善于用一些现代的工具啊。

电费水平

目前母鸡,等我过两天观察观察。