1 Commits
Author SHA1 Message Date
HassBox 3f3f7c0bcc deploy 2024-07-12 09:44:26 +08:00
13 changed files with 622 additions and 610 deletions
+1 -29
View File
@@ -1,29 +1 @@
# 国家电网 # State Grid
集成国家电网每日用电等数据,支持多户号,阶梯用电。
## 安装/更新
#### 方法 1: 通过`Samba`或`SFTP`手动安装
下载并复制`custom_components/state_gird`文件夹到 Home Assistant 根目录下的`custom_components`文件夹
#### 方法 2: 通过`SSH`或`Terminal & SSH`加载项执行一键安装命令
```shell
curl -fsSL get.hassbox.cn/state_grid | bash
```
#### 方法 3: 通过`shell_command`服务
1. 复制下面的代码到 Home Assistant 配置文件`configuration.yaml`
```yaml
shell_command:
install_state_grid: |-
curl -fsSL get.hassbox.cn/state_grid | bash
```
2. 重启 Home Assistant
3. 在 Home Assistant 开发者工具中调用此服务[`service: shell_command.install_state_grid`](https://my.home-assistant.io/redirect/developer_call_service/?service=shell_command.install_state_grid)
+2 -2
View File
@@ -202,13 +202,12 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
async def async_step_check_qr_code(self, user_input=None): async def async_step_check_qr_code(self, user_input=None):
result = await self.data_client.check_qr_code() result = await self.data_client.check_qr_code()
if result['errcode'] != 0: if result['errcode'] != 0:
return self.async_abort( return self.async_abort(
reason="check_qr_code_error", reason="check_qr_code_error",
description_placeholders={'errmsg': result["errmsg"]} description_placeholders={'errmsg': result["errmsg"]}
) )
await self.data_client.refresh_data(force_refresh=True)
return self.async_create_entry( return self.async_create_entry(
title="国家电网", title="国家电网",
data={} data={}
@@ -248,6 +247,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
code = user_input['code'] code = user_input['code']
result = await self.data_client.verfiy_phone_code(code) result = await self.data_client.verfiy_phone_code(code)
if result['errcode'] == 0: if result['errcode'] == 0:
await self.data_client.refresh_data(force_refresh=True)
return self.async_create_entry( return self.async_create_entry(
title="国家电网", title="国家电网",
data={} data={}
+2 -2
View File
@@ -1,4 +1,4 @@
DOMAIN = 'state_grid' DOMAIN = "state_grid"
PACKAGE_NAME = "custom_components.state_grid" PACKAGE_NAME = "custom_components.state_grid"
VERSION = "0.0.4" VERSION = "0.1.3"
VERSION_STORAGE = 1 VERSION_STORAGE = 1
+367 -320
View File
@@ -1,345 +1,392 @@
BZ='params4' _B4='get_door_daily_bill_api'
BY='params3' _B3='startTime'
BX='params1' _B2='constType'
BW='queryYear' _B1='provinceCode'
BV='provinceCode' _B0='access_token'
BU='sceneType' _A_='businessType'
BT='consNoSrc' _Az='qrCodeSerial'
BS='access_token' _Ay='redirect_url'
BR='codeKey' _Ax='_access_token'
BQ='businessType' _Aw='dataVersion'
BP='Channels' _Av='refresh_interval'
BO='qrCodeSerial' _Au='doorAccountDict'
BN='redirect_url' _At='refreshToken'
BM='_access_token' _As='accessToken'
BL='is_debug' _Ar='/osg-web0004/member/c24/f01'
BK='refresh_interval' _Aq='BCP_00026'
BJ='doorAccountDict' _Ap='serviceCode_smt'
BI='refreshToken' _Ao='WEBA10070900'
BH='accessToken' _An='serviceType'
BG='/osg-web0004/member/c24/f01' _Am='jM_custType'
BF='BCP_00026' _Al='jM_busiTypeCode'
BE='serviceCode_smt' _Ak='doorNumberManeger'
BD='WEBA10070900' _Aj='month_t_ele_num'
BC='serviceType' _Ai='month_n_ele_num'
BB='jM_custType' _Ah='month_v_ele_num'
BA='jM_busiTypeCode' _Ag='month_p_ele_num'
B9='01008183' _Af='month_ele_num'
B8='0101003' _Ae='thisTPq'
B7='submit' _Ad='thisNPq'
B2='consType' _Ac='thisVPq'
B1='constType' _Ab='thisPPq'
B0='powerUserList' _Aa='%Y%m%d'
A_='publicKey' _AZ='params4'
Az='WEBA10070800' _AY='params3'
Ay='timeDay' _AX='params1'
Ax='105' _AW='queryYear'
Aw='111' _AV='userAccountId'
Av='0901' _AU='powerUserList'
Au='WEBA10070700' _AT='publicKey'
At='102' _AS='WEBA10070800'
As='0101143' _AR='timeDay'
Ar='channelNo' _AQ='WEBA10070700'
Ae='latestBillMonth' _AP='channelNo'
Ad='yearTotalCost' _AO='dayElePq'
Ac='userAccountId' _AN='sevenEleList'
Ab='0000' _AM='month'
Aa='refresh_token' _AL='yearTotalCost'
AZ='web' _AK='consType'
AY='skey' _AJ='0000'
AX='userInfo' _AI='refresh_token'
AW=True _AH='skey'
AV='215' _AG='userInfo'
AU='0101046' _AF='0101046'
AK='accountBalance' _AE='billYear'
AJ='proCode' _AD='proCode'
AI='loginAccount' _AC='loginAccount'
AH='keyCode' _AB='list'
AG='querytypeCode' _AA='keyCode'
AF='01010049' _A9='querytypeCode'
AE='doorNumberManeger' _A8='01010049'
AD='monthBillList' _A7='account'
AC='list' _A6='daily_bill_list'
AB='userName' _A5='account_balance'
AA='acctId' _A4='provinceId'
A9='resultCode' _A3='userName'
A8='quInfo' _A2='acctId'
A7='BCP_000026' _A1='resultCode'
A6='app' _A0='BCP_000026'
A5='WEBALIPAY_01' _z='app'
A4='order' _y='WEBALIPAY_01'
A3='state_grid' _x='order'
z=False _w='state_grid'
y='authFlag' _v='latestBillMonth'
x='09' _u='quInfo'
w='0101183' _t='authFlag'
v='stepelect' _s='09'
u='account' _r='0101183'
t=len _q='stepelect'
s='consNo_dst' _p='consNo'
r='token' _o=True
q='0101154' _n='0101154'
p='getday' _m='monthBillList'
n='consNo' _l='bizrt'
m='bizrt' _k='token'
l='clearCache' _j='timestamp'
k='timestamp' _i=False
i='errmsg' _h='month_ele'
h='promotCode' _g='errmsg'
g='01' _f='clearCache'
f='SGAPP' _e='SGAPP'
e='devciceId' _d='orgNo'
d='devciceIp' _c='consNo_dst'
c='orgNo' _b='promotCode'
b='tenant' _a='01'
a='member' _Z='devciceId'
Z=str _Y='devciceIp'
Y='daily_bill_list' _X='proNo'
X='proNo' _W='tenant'
W='promotType' _V='member'
V='target' _U='promotType'
U='userId' _T='getday'
T='srvrt' _S='srvrt'
S='subBusiTypeCode' _R='userId'
R='serCat' _Q='subBusiTypeCode'
Q='serialNo' _P='target'
O='0902' _O='serCat'
N='srvCode' _N='serialNo'
M='uscInfo' _M='0902'
L=None _L='srvCode'
K='busiTypeCode' _K='busiTypeCode'
J='code' _J='uscInfo'
I='channelCode' _I='channelCode'
H='1' _H='code'
G='source' _G='1'
E='funcCode' _F=None
D='serviceCode' _E='source'
C='errcode' _D='funcCode'
B='data' _C='errcode'
A='' _B='serviceCode'
import json as AL,time as Af,aiohttp as Ag,urllib.parse,datetime as j _A='data'
from.utils.logger import LOGGER as A0 import json,time,aiohttp,urllib.parse,datetime
from.utils.store import async_save_to_store as Ba from.const import VERSION
from.utils.crypt import a as AM,b as B3,c as A1,d as AN,e as Ah from.utils.logger import LOGGER
o='3def6c365d284881bf1a9b2b502ee68c' from.utils.store import async_save_to_store
Ai='ab7357dae64944a197ace37398897f64' from.utils.crypt import a,b,c,d,e
F={M:{a:O,d:A,e:A,b:A3},G:f,V:'32101',I:O,Ar:O,'toPublish':g,'siteId':'2012000000033700',N:A,Q:A,E:A,D:{A4:q,'uploadPic':'0101296','pauseSCode':'0101250','pauseTCode':'0101251','listconsumers':'0101093','messageList':'0101343',B7:B8,'sbcMsg':'0101210','powercut':'0104514','BkAuth01':'f15','BkAuth02':'f18','BkAuth03':'f02','BkAuth04':'f17','BkAuth05':'f05','BkAuth06':'f16','BkAuth07':'f01','BkAuth08':'f03'},'electricityArchives':{'servicecode':'0104505',G:O},'subscriptionList':{N:'APP_SGPMS_05_030',Q:'22',I:O,E:'22',V:'-1'},'userInformation':{D:B9,G:f},'userInform':{D:w,G:f},'elesum':{I:O,E:A5,h:H,W:H,D:As,G:A6},u:{I:O,E:'WEBA1007200'},AE:{G:O,V:'-1',I:x,Ar:x,D:AF,E:'WEBA40050000',M:{a:O,d:A,e:A,b:A3}},'doorAuth':{G:f,D:'f04'},'xinZ':{R:'101',BA:'101','fJ_busiTypeCode':At,BB:'03','fJ_custType':'02',BC:g,S:A,E:Au,A4:q,G:f,AG:H},'onedo':{D:AU,G:f,E:Au,'queryType':'03'},'xinHuTongDian':{R:'110',K:'211',S:'21102',E:'WEBA10071200',I:O,G:x,D:w},'company':{R:'104',E:Au,BC:'02',AG:H,y:H,G:f,A4:q},'charge':{I:x,E:'WEBA10071300',Ar:Av,R:At,BB:g,BA:At},'other':{I:x,E:'WEBA10079700',R:'129',K:'999',S:'21501',D:A7,N:A,Q:A},'vatchange':{B7:B8,K:'320',S:A,R:'115',E:'WEBA10074000',y:H},'bill':{l:H,E:A5,W:H,D:A7},v:{I:O,E:A5,W:H,l:x,D:A7,G:A6},p:{I:O,l:'11',E:A5,h:H,W:H,D:A7,G:A6},'mouthOut':{I:O,l:'11',E:A5,h:H,W:H,D:A7,G:A6},'meter':{R:'114',K:'304',E:'WEBA10071000',S:A,D:AU,Q:A},'complaint':{K:'005','srvMode':O,'anonymousFlag':'0','replyMode':g,'retvisitFlag':g},'report':{K:'006'},'tradewinds':{K:'019'},'somesay':{K:'091'},'faultrepair':{E:BD,D:w,R:Aw,K:'001',S:'21505'},'electronicInvoice':{R:Ax,K:'0'},'rename':{D:AU,E:'WEBA10076100',K:'210',R:'109',y:H,'gh_busiTypeCode':'211','gh_subusi':'21101',Q:A,N:A},'pause':{S:A,D:AF,E:'WEBA10073600',R:'107',K:'203','jr_busi':'201',Q:A,N:A},'capacityRecovery':{D:AF,G:f,N:A,Q:A,E:'WEBA10073700','busiTypeCode_stop':'204','busiTypeCode_less':'202',K:'202',S:A,R:'108',Ay:'5',y:H},'electricityPriceChange':{D:w,K:AV,S:'21502',R:'113',y:H,Ay:'15',E:'WEBA10073900WEB',N:A,Q:A},'electricityPriceStrategyChange':{D:B9,K:AV,S:'21506',R:'160',E:'WEBV00000517WEB',N:A,Q:A},'eemandValueAdjustment':{D:w,N:A,Q:A,R:'112',E:'WEBA10073800',K:AV,S:'21504',y:H,Ay:'5','getMonthServiceCode':AU},'businessProgress':{D:w,N:g,E:'WEB01'},'increase':{G:f,Q:A,N:A,BE:AF,D:q,A4:q,E:Az,AG:H,R:'106',K:Aw,S:A},'fjincrea':{R:Ax,K:'110',S:A,G:f,E:Az,Q:A,N:A,BE:AF,D:q,A4:q,AG:H},'persIncrea':{R:Ax,K:'109',A4:q,S:A,G:f,E:Az,AG:H},'fgdChange':{D:w,N:g,I:x,E:BD,K:AV,S:'21505',R:Aw,y:H},'createOrder':{I:O,E:A5,N:'BCP_000001','chargeMode':'02','conType':g,'bizTypeId':'BT_ELEC'},'largePopulation':{K:'383',E:'WEBA10076800',S:A,N:A,W:A,h:A,I:Av,R:'383',D:A,Q:A},'biaoJiCode':{D:'0104507',G:'1704',I:'1704'},'twoGuar':{K:'402',S:'40201',E:'web_twoGuar'},'electTrend':{D:BF,I:O},'emergency':{D:BF,E:'A10000000',I:O},'infoPublic':{D:'2545454',G:A6}} configuration={_J:{_V:_M,_Y:'',_Z:'',_W:_w},_E:_e,_P:'32101',_I:_M,_AP:_M,'toPublish':_a,'siteId':'2012000000033700',_L:'',_N:'',_D:'',_B:{_x:_n,'uploadPic':'0101296','pauseSCode':'0101250','pauseTCode':'0101251','listconsumers':'0101093','messageList':'0101343','submit':'0101003','sbcMsg':'0101210','powercut':'0104514','BkAuth01':'f15','BkAuth02':'f18','BkAuth03':'f02','BkAuth04':'f17','BkAuth05':'f05','BkAuth06':'f16','BkAuth07':'f01','BkAuth08':'f03'},'electricityArchives':{'servicecode':'0104505',_E:_M},'subscriptionList':{_L:'APP_SGPMS_05_030',_N:'22',_I:_M,_D:'22',_P:'-1'},'userInformation':{_B:'01008183',_E:_e},'userInform':{_B:_r,_E:_e},'elesum':{_I:_M,_D:_y,_b:_G,_U:_G,_B:'0101143',_E:_z},_A7:{_I:_M,_D:'WEBA1007200'},_Ak:{_E:_M,_P:'-1',_I:_s,_AP:_s,_B:_A8,_D:'WEBA40050000',_J:{_V:_M,_Y:'',_Z:'',_W:_w}},'doorAuth':{_E:_e,_B:'f04'},'xinZ':{_O:'101',_Al:'101','fJ_busiTypeCode':'102',_Am:'03','fJ_custType':'02',_An:_a,_Q:'',_D:_AQ,_x:_n,_E:_e,_A9:_G},'onedo':{_B:_AF,_E:_e,_D:_AQ,'queryType':'03'},'xinHuTongDian':{_O:'110',_K:'211',_Q:'21102',_D:'WEBA10071200',_I:_M,_E:_s,_B:_r},'company':{_O:'104',_D:_AQ,_An:'02',_A9:_G,_t:_G,_E:_e,_x:_n},'charge':{_I:_s,_D:'WEBA10071300',_AP:'0901',_O:'102',_Am:_a,_Al:'102'},'other':{_I:_s,_D:'WEBA10079700',_O:'129',_K:'999',_Q:'21501',_B:_A0,_L:'',_N:''},'vatchange':{'submit':'0101003',_K:'320',_Q:'',_O:'115',_D:'WEBA10074000',_t:_G},'bill':{_f:_G,_D:_y,_U:_G,_B:_A0},_q:{_I:_M,_D:_y,_U:_G,_f:_s,_B:_A0,_E:_z},_T:{_I:_M,_f:'11',_D:_y,_b:_G,_U:_G,_B:_A0,_E:_z},'mouthOut':{_I:_M,_f:'11',_D:_y,_b:_G,_U:_G,_B:_A0,_E:_z},'meter':{_O:'114',_K:'304',_D:'WEBA10071000',_Q:'',_B:_AF,_N:''},'complaint':{_K:'005','srvMode':_M,'anonymousFlag':'0','replyMode':_a,'retvisitFlag':_a},'report':{_K:'006'},'tradewinds':{_K:'019'},'somesay':{_K:'091'},'faultrepair':{_D:_Ao,_B:_r,_O:'111',_K:'001',_Q:'21505'},'electronicInvoice':{_O:'105',_K:'0'},'rename':{_B:_AF,_D:'WEBA10076100',_K:'210',_O:'109',_t:_G,'gh_busiTypeCode':'211','gh_subusi':'21101',_N:'',_L:''},'pause':{_Q:'',_B:_A8,_D:'WEBA10073600',_O:'107',_K:'203','jr_busi':'201',_N:'',_L:''},'capacityRecovery':{_B:_A8,_E:_e,_L:'',_N:'',_D:'WEBA10073700','busiTypeCode_stop':'204','busiTypeCode_less':'202',_K:'202',_Q:'',_O:'108',_AR:'5',_t:_G},'electricityPriceChange':{_B:_r,_K:'215',_Q:'21502',_O:'113',_t:_G,_AR:'15',_D:'WEBA10073900WEB',_L:'',_N:''},'electricityPriceStrategyChange':{_B:'01008183',_K:'215',_Q:'21506',_O:'160',_D:'WEBV00000517WEB',_L:'',_N:''},'eemandValueAdjustment':{_B:_r,_L:'',_N:'',_O:'112',_D:'WEBA10073800',_K:'215',_Q:'21504',_t:_G,_AR:'5','getMonthServiceCode':_AF},'businessProgress':{_B:_r,_L:_a,_D:'WEB01'},'increase':{_E:_e,_N:'',_L:'',_Ap:_A8,_B:_n,_x:_n,_D:_AS,_A9:_G,_O:'106',_K:'111',_Q:''},'fjincrea':{_O:'105',_K:'110',_Q:'',_E:_e,_D:_AS,_N:'',_L:'',_Ap:_A8,_B:_n,_x:_n,_A9:_G},'persIncrea':{_O:'105',_K:'109',_x:_n,_Q:'',_E:_e,_D:_AS,_A9:_G},'fgdChange':{_B:_r,_L:_a,_I:_s,_D:_Ao,_K:'215',_Q:'21505',_O:'111',_t:_G},'createOrder':{_I:_M,_D:_y,_L:'BCP_000001','chargeMode':'02','conType':_a,'bizTypeId':'BT_ELEC'},'largePopulation':{_K:'383',_D:'WEBA10076800',_Q:'',_L:'',_U:'',_b:'',_I:'0901',_O:'383',_B:'',_N:''},'biaoJiCode':{_B:'0104507',_E:'1704',_I:'1704'},'twoGuar':{_K:'402',_Q:'40201',_D:'web_twoGuar'},'electTrend':{_B:_Aq,_I:_M},'emergency':{_B:_Aq,_D:'A10000000',_I:_M},'infoPublic':{_B:'2545454',_E:_z}}
B4='https://www.95598.cn/api' appKey='3def6c365d284881bf1a9b2b502ee68c'
B5='/oauth2/outer/c02/f02' appSecret='ab7357dae64944a197ace37398897f64'
Aj='/osg-open-uc0001/member/c8/f24' baseApi='https://www.95598.cn/api'
Ak='/osg-web0004/open/c50/f02' get_request_key_api='/oauth2/outer/c02/f02'
Al='/osg-uc0013/member/c4/f04' get_qr_code_api='/osg-open-uc0001/member/c8/f24'
Am='/osg-open-uc0001/member/c8/f04' get_qr_code_status_api='/osg-web0004/open/c50/f02'
An='/osg-uc0013/member/c4/f02' get_qr_code_token_api='/osg-uc0013/member/c4/f04'
B6='/osg-open-uc0001/member/c8/f11' send_code_api='/osg-open-uc0001/member/c8/f04'
Ao='/oauth2/oauth/authorize' code_login_api='/osg-uc0013/member/c4/f02'
AO='/oauth2/outer/getWebToken' getCertificationApi='/osg-open-uc0001/member/c8/f11'
Ap='/oauth2/outer/refresh_web_token' get_request_authorize_api='/oauth2/oauth/authorize'
Aq='/osg-open-uc0001/member/c9/f02' get_web_token_api='/oauth2/outer/getWebToken'
AP='/osg-open-bc0001/member/c05/f01' refresh_web_token_api='/oauth2/outer/refresh_web_token'
AQ='/osg-open-bc0001/member/c01/f02' get_door_number_api='/osg-open-uc0001/member/c9/f02'
AR='/osg-open-bc0001/member/c04/f03' get_door_balance_api='/osg-open-bc0001/member/c05/f01'
AS=BG get_door_bill_api='/osg-open-bc0001/member/c01/f02'
AT=BG get_door_ladder_api='/osg-open-bc0001/member/c04/f03'
Bb=[Aj,Ak,Al,Am,An] getJiaoFeiRecordApi=_Ar
Bc=[Ak,Al,Am,An,B6,Ao,AO,Ap,Aq,AP,AQ,AR,AS,AT] get_door_daily_bill_api=_Ar
Bd=[Aq,AP,AQ,AR,AS,AT] sessionIdControlApiList=[get_qr_code_api,get_qr_code_status_api,get_qr_code_token_api,send_code_api,code_login_api]
Be=[B6,AP,AQ,AR,AS,AT] keyCodeControlApiList=[get_qr_code_status_api,get_qr_code_token_api,send_code_api,code_login_api,getCertificationApi,get_request_authorize_api,get_web_token_api,refresh_web_token_api,get_door_number_api,get_door_balance_api,get_door_bill_api,get_door_ladder_api,getJiaoFeiRecordApi,get_door_daily_bill_api]
def A2(data):return AL.dumps(data,separators=(',',':'),ensure_ascii=z) authControlApiList=[get_door_number_api,get_door_balance_api,get_door_bill_api,get_door_ladder_api,getJiaoFeiRecordApi,get_door_daily_bill_api]
def P(data,key): tControlApiList=[getCertificationApi,get_door_balance_api,get_door_bill_api,get_door_ladder_api,getJiaoFeiRecordApi,get_door_daily_bill_api]
def json_dumps(data):return json.dumps(data,separators=(',',':'),ensure_ascii=_i)
def normal_round(num,ndigits=0):
A=ndigits
if A==0:return int(num+.5)
else:B=10**A;return int(num*B+.5)/B
def catchFloat(data,key):
if key in data: if key in data:
try:return float(data[key]) try:return normal_round(float(data[key]),2)
except:return 0 except:return 0
else:return 0 else:return 0
class StateGridDataClient: class StateGridDataClient:
hass=L;session=L;keyCode=L;publicKey=L;need_login=z;phone=L;codeKey=L;serialNo=L;qrCodeSerial=L;userInfo=L;accountInfo=L;powerUserList=L;doorAccountDict={};cookie=[];timestamp=int(Af.time()*1000);accessToken=L;refreshToken=L;token=L;expirationDate=L;refresh_interval=12;is_debug=z hass=_F;session=_F;dataVersion=_F;keyCode=_F;publicKey=_F;need_login=_i;retry_times=0;phone=_F;codeKey=_F;serialNo=_F;qrCodeSerial=_F;userInfo=_F;accountInfo=_F;powerUserList=_F;doorAccountDict={};cookie=[];timestamp=int(time.time()*1000);accessToken=_F;refreshToken=_F;token=_F;expirationDate=_F;refresh_interval=6;is_debug=_i
def __init__(A,hass,config=L): def __init__(A,hass,config=_F):
B=config;A.hass=hass;C=Ag.TCPConnector(ssl=z);D=Ag.CookieJar(quote_cookie=AW);A.session=Ag.ClientSession(cookie_jar=D,connector=C) B=config;A.hass=hass;C=aiohttp.TCPConnector(ssl=_i);D=aiohttp.CookieJar(quote_cookie=_o);A.session=aiohttp.ClientSession(cookie_jar=D,connector=C)
if B is not L: if B is not _F:
try:A.keyCode=B[AH];A.publicKey=B[A_];A.accessToken=B[BH];A.refreshToken=B[BI];A.token=B[r];A.userInfo=B[AX];A.powerUserList=B[B0];A.doorAccountDict=B[BJ];A.refresh_interval=B[BK];A.is_debug=B[BL] try:A.keyCode=B[_AA];A.publicKey=B[_AT];A.accessToken=B[_As];A.refreshToken=B[_At];A.token=B[_k];A.userInfo=B[_AG];A.powerUserList=B[_AU];A.doorAccountDict=B[_Au];A.refresh_interval=B[_Av];A.is_debug=B['is_debug'];A.dataVersion=B[_Aw]
except Exception as E:A0.error(E) except Exception as E:LOGGER.error(E)
async def save_data(A):B={};B[AH]=A.keyCode;B[A_]=A.publicKey;B[BH]=A.accessToken;B[BI]=A.refreshToken;B[r]=A.token;B[AX]=A.userInfo;B[B0]=A.powerUserList;B[BJ]=A.doorAccountDict;B[BK]=A.refresh_interval;B[BL]=A.is_debug;await Ba(A.hass,'state_grid.config',B) async def save_data(B):A={};A[_AA]=B.keyCode;A[_AT]=B.publicKey;A[_As]=B.accessToken;A[_At]=B.refreshToken;A[_k]=B.token;A[_AG]=B.userInfo;A[_AU]=B.powerUserList;A[_Au]=B.doorAccountDict;A[_Av]=B.refresh_interval;A['is_debug']=B.is_debug;A[_Aw]=VERSION;await async_save_to_store(B.hass,'state_grid.config',A)
def encrypt_post_data(B,data):C={BM:B.accessToken[t(B.accessToken)//2:]if B.accessToken else A,'_t':B.token[t(B.token)//2:]if B.token else A,'_data':data,k:B.timestamp};return B.encrypt_wapper_data(C) def encrypt_post_data(A,data):B={_Ax:A.accessToken[len(A.accessToken)//2:]if A.accessToken else'','_t':A.token[len(A.token)//2:]if A.token else'','_data':data,_j:A.timestamp};return A.encrypt_wapper_data(B)
def encrypt_wapper_data(A,data):C=AM(A2(data),A.keyCode);return{B:C+A1(C+Z(A.timestamp)),AY:AN(A.keyCode,A.publicKey),k:Z(A.timestamp)} def encrypt_wapper_data(A,data):B=a(json_dumps(data),A.keyCode);return{_A:B+c(B+str(A.timestamp)),_AH:d(A.keyCode,A.publicKey),_j:str(A.timestamp)}
def handle_request_result_message(F,api,result): def handle_request_result_message(E,api,result):
E='message';D='resultMessage';A=result;C=L D='message';C='resultMessage';A=result;B=_F
if B in A and T in A[B]and D in A[B][T]:C=A[B][T][D] if _A in A and _S in A[_A]and C in A[_A][_S]:B=A[_A][_S][C]
elif T in A and D in A[T]:C=A[T][D] elif _S in A and C in A[_S]:B=A[_S][C]
elif E in A:C=A[E] elif D in A:B=A[D]
else:C=A2(A) else:B=json_dumps(A)
if F.is_debug:A0.error(api+': '+C);A0.error(A2(A)) if E.is_debug:LOGGER.error(api+': '+B);LOGGER.error(json_dumps(A))
return B
async def __fetch_safe(C,api,data):
B=await C.__fetch(api,data)
if _H not in B:return B
A=B[_H]
if 10015==A or 10108==A or 10009==A or 10207==A or 10005==A or 10010==A or 30010==A or 10002==A:
await C.__refresh_token()
if C.need_login is _o:return B
else:return await C.__fetch(api,data)
else:return B
async def __fetch(B,api,data,header=_F):
T='encryptData';S='464606a4-184c-4beb-b442-2ab7761d0796';R='key_code';Q='state';P='sign';O='grant_type';N='application/json;charset=UTF-8';M='Content-Type';L=header;K='client_secret';I='client_id';E=api;B.timestamp=int(time.time()*1000);D=B.timestamp
if B.keyCode is _F:B.keyCode=e(32,16,2)
F=B.keyCode;G={'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36','Accept':N,M:N,'version':'1.0',_E:'0901',_j:str(D),'wsgwType':'web','appKey':appKey};A=data
if E==get_request_key_api:A={I:appKey,K:appSecret};H=a(json_dumps(A),F);A={_A:H+c(H+str(D)),_AH:d(F,'042BC7AD510BF9793B7744C8854C56A8C95DD1027EE619247A332EC6ED5B279F435A23D62441FE861F4B0C963347ECD5792F380B64CA084BE8BE41151F8B8D19C8'),I:appKey,_j:str(D)}
elif E==get_qr_code_api:A={_Ax:'','_t':'','_data':A,_j:D}
elif E==get_request_authorize_api:
A={I:appKey,'response_type':_H,_Ay:'/test',_j:D,'rsi':B.token};A=urllib.parse.urlencode(A);G[M]='application/x-www-form-urlencoded; charset=UTF-8';G[_AA]=F
async with B.session.post(baseApi+E,data=A,headers=G)as J:B.session.cookie_jar.update_cookies(J.cookies);C=await J.json();C=b(C[_A],B.token);C=json.loads(C);return C
elif E==get_web_token_api:A={O:'authorization_code',P:c(appKey+str(D)),K:appSecret,Q:S,R:F,I:appKey,_j:D,_H:A[_H]};H=a(json_dumps(A),F);A={_A:H+c(H+str(D)),_AH:d(F,B.publicKey),_j:str(D)}
elif E==refresh_web_token_api:A={O:_AI,P:c(appKey+str(D)),K:appSecret,Q:S,R:F,I:appKey,_j:D,_AI:B.refreshToken};H=a(json_dumps(A),F);A={_A:H+c(H+str(D)),_AH:d(F,B.publicKey),_j:str(D)};E=get_web_token_api
else:A=B.encrypt_post_data(A)
if L is not _F:G.update(L)
if E in sessionIdControlApiList:G['sessionId']='web'+str(D)
if E in keyCodeControlApiList:G[_AA]=F
if E in authControlApiList:G['Authorization']='Bearer '+B.accessToken[:len(B.accessToken)//2]
if E in tControlApiList:G['t']=B.token[:len(B.token)//2]
async with B.session.post(baseApi+E,json=A,headers=G)as J:
C=await J.text()
if C.startswith('{'):
C=json.loads(C)
if T in C:C=b(C[T],F);C=json.loads(C)
return C return C
async def fetch(D,api,data,header=L):
Y='encryptData';X='464606a4-184c-4beb-b442-2ab7761d0796';W='key_code';V='state';U='sign';T='grant_type';S='application/json;charset=UTF-8';R='Content-Type';Q=header;P='client_secret';N='client_id';H=api;D.timestamp=int(Af.time()*1000);F=D.timestamp
if D.keyCode is L:D.keyCode=Ah(32,16,2)
I=D.keyCode;K={'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36','Accept':S,R:S,'version':'1.0',G:Av,k:Z(F),'wsgwType':AZ,'appKey':o};C=data
if H==B5:C={N:o,P:Ai};M=AM(A2(C),I);C={B:M+A1(M+Z(F)),AY:AN(I,'042BC7AD510BF9793B7744C8854C56A8C95DD1027EE619247A332EC6ED5B279F435A23D62441FE861F4B0C963347ECD5792F380B64CA084BE8BE41151F8B8D19C8'),N:o,k:Z(F)}
elif H==Aj:C={BM:A,'_t':A,'_data':C,k:F}
elif H==Ao:
C={N:o,'response_type':J,BN:'/test',k:F,'rsi':D.token};C=urllib.parse.urlencode(C);K[R]='application/x-www-form-urlencoded; charset=UTF-8';K[AH]=I
async with D.session.post(B4+H,data=C,headers=K)as O:D.session.cookie_jar.update_cookies(O.cookies);E=await O.json();E=B3(E[B],D.token);E=AL.loads(E);return E
elif H==AO:C={T:'authorization_code',U:A1(o+Z(F)),P:Ai,V:X,W:I,N:o,k:F,J:C[J]};M=AM(A2(C),I);C={B:M+A1(M+Z(F)),AY:AN(I,D.publicKey),k:Z(F)}
elif H==Ap:C={T:Aa,U:A1(o+Z(F)),P:Ai,V:X,W:I,N:o,k:F,Aa:D.refreshToken};M=AM(A2(C),I);C={B:M+A1(M+Z(F)),AY:AN(I,D.publicKey),k:Z(F)};H=AO
else:C=D.encrypt_post_data(C)
if Q is not L:K.update(Q)
if H in Bb:K['sessionId']=AZ+Z(F)
if H in Bc:K[AH]=I
if H in Bd:K['Authorization']='Bearer '+D.accessToken[:t(D.accessToken)//2]
if H in Be:K['t']=D.token[:t(D.token)//2]
async with D.session.post(B4+H,json=C,headers=K)as O:
E=await O.text()
if E.startswith('{'):
E=AL.loads(E)
if Y in E:E=B3(E[Y],I);E=AL.loads(E)
return E
async def __get_request_key(A): async def __get_request_key(A):
A.keyCode=L;D=await A.fetch(B5,{});E=A.handle_request_result_message('get_request_key_api',D) A.keyCode=_F;B=await A.__fetch(get_request_key_api,{});C=A.handle_request_result_message('get_request_key_api',B)
if D[J]==H:A.keyCode=D[B][AH];A.publicKey=D[B][A_];return{C:0} if B[_H]==_G:A.keyCode=B[_A][_AA];A.publicKey=B[_A][_AT];return{_C:0}
return{C:1,i:E} return{_C:1,_g:C}
async def __get_qr_code(E): async def __get_qr_code(B):
F={M:{d:A,b:A3,a:O,e:A},A8:{'optType':g,Q:Ah(28,10,1)}};D=await E.fetch(Aj,F);G=E.handle_request_result_message('get_qr_code_api',D) C={_J:{_Y:'',_W:_w,_V:_M,_Z:''},_u:{'optType':_a,_N:e(28,10,1)}};A=await B.__fetch(get_qr_code_api,C);D=B.handle_request_result_message('get_qr_code_api',A)
if D[J]==1: if A[_H]==1:
if D[B]and D[B][T]and D[B][T][A9]==Ab:E.qrCodeSerial=D[B][m][BO];H=D[B][m]['qrCode'];return{C:0,B:H} if A[_A]and A[_A][_S]and A[_A][_S][_A1]==_AJ:B.qrCodeSerial=A[_A][_l][_Az];E=A[_A][_l]['qrCode'];return{_C:0,_A:E}
return{C:1,i:G} return{_C:1,_g:D}
async def __get_qr_code_status(D): async def __get_qr_code_status(B):
E={m:{BO:D.qrCodeSerial}};F={r:'98'+Ah(10,10,1)};A=await D.fetch(Ak,E,F);G=D.handle_request_result_message('get_qr_code_status_api',A) C={_l:{_Az:B.qrCodeSerial}};D={_k:'98'+e(10,10,1)};A=await B.__fetch(get_qr_code_status_api,C,D);E=B.handle_request_result_message('get_qr_code_status_api',A)
if J in A and A[J]==1: if _H in A and A[_H]==1:
if B in A and A[B]!='null':D.token=A[B];return{C:0} if _A in A and A[_A]!='null':B.token=A[_A];return{_C:0}
else:return{C:1,i:'未使用网上国网 App 扫码或确认登录'} else:return{_C:1,_g:'未使用网上国网 App 扫码或确认登录'}
return{C:1,i:G} return{_C:1,_g:E}
async def __get_qr_code_token(B): async def __get_qr_code_token(B):
D={M:{b:A3,a:O,'isEncrypt':AW},r:B.token};A=await B.fetch(Al,D);E=B.handle_request_result_message('get_qr_code_token_api',A) C={_J:{_W:_w,_V:_M,'isEncrypt':_o},_k:B.token};A=await B.__fetch(get_qr_code_token_api,C);D=B.handle_request_result_message('get_qr_code_token_api',A)
if T in A and A9 in A[T]and A[T][A9]==Ab:B.userInfo=A[m][AX];return{C:0} if _S in A and _A1 in A[_S]and A[_S][_A1]==_AJ:B.userInfo=A[_l][_AG];return{_C:0}
return{C:1,i:E} return{_C:1,_g:D}
async def __send_code(E,phone): async def __send_code(B,phone):
F=phone;E.phone=F;G={M:{d:A,b:A3,a:O,e:A},A8:{'sendType':'0',u:F,BQ:'login','accountType':A},BP:AZ};D=await E.fetch(Am,G);H=E.handle_request_result_message('send_code_api',D) C=phone;B.phone=C;D={_J:{_Y:'',_W:_w,_V:_M,_Z:''},_u:{'sendType':'0',_A7:C,_A_:'login','accountType':''},'Channels':'web'};A=await B.__fetch(send_code_api,D);E=B.handle_request_result_message('send_code_api',A)
if D[J]==1: if A[_H]==1:
if D[B]and D[B][T]and D[B][T][A9]==Ab:E.codeKey=D[B][m][BR];return{C:0} if A[_A]and A[_A][_S]and A[_A][_S][_A1]==_AJ:B.codeKey=A[_A][_l]['codeKey'];return{_C:0}
return{C:1,i:H} return{_C:1,_g:E}
async def __verfiy_code(B,code): async def __verfiy_code(A,code):
E={M:{d:A,b:A3,a:O,e:A},A8:{u:B.phone,BQ:'login',J:code,'optSys':'ios','pushId':'00000',BR:B.codeKey},BP:AZ};D=await B.fetch(An,E);F=B.handle_request_result_message('code_login_api',D) C={_J:{_Y:'',_W:_w,_V:_M,_Z:''},_u:{_A7:A.phone,_A_:'login',_H:code,'optSys':'ios','pushId':'00000','codeKey':A.codeKey},'Channels':'web'};B=await A.__fetch(code_login_api,C);D=A.handle_request_result_message('code_login_api',B)
if T in D and A9 in D[T]and D[T][A9]==Ab:B.token=D[m][r];B.userInfo=D[m][AX][0];return{C:0} if _S in B and _A1 in B[_S]and B[_S][_A1]==_AJ:A.token=B[_l][_k];A.userInfo=B[_l][_AG][0];return{_C:0}
return{C:1,i:F} return{_C:1,_g:D}
async def __get_request_authorize(D): async def __get_request_authorize(B):
A=await D.fetch(Ao,{});G=D.handle_request_result_message('get_request_authorize_api',A) A=await B.__fetch(get_request_authorize_api,{});E=B.handle_request_result_message('get_request_authorize_api',A)
if J in A and A[J]==H:E=A[B][BN];F=E.rfind('code=');D.authorizeCode=E[F+5:F+5+32];return{C:0} if _H in A and A[_H]==_G:C=A[_A][_Ay];D=C.rfind('code=');B.authorizeCode=C[D+5:D+5+32];return{_C:0}
return{C:1,i:G} return{_C:1,_g:E}
async def __get_web_token(A): async def __get_web_token(A):
E={J:A.authorizeCode};D=await A.fetch(AO,E);F=A.handle_request_result_message('get_web_token_api',D) C={_H:A.authorizeCode};B=await A.__fetch(get_web_token_api,C);D=A.handle_request_result_message('get_web_token_api',B)
if J in D and D[J]==H:A.accessToken=D[B][BS];A.refreshToken=D[B][Aa];return{C:0} if _H in B and B[_H]==_G:A.accessToken=B[_A][_B0];A.refreshToken=B[_A][_AI];return{_C:0}
return{C:1,i:F} return{_C:1,_g:D}
async def __refresh_web_token(D): async def __refresh_web_token(B):
A=await D.fetch(Ap,{});E=D.handle_request_result_message('refresh_web_token_api',A) A=await B.__fetch(refresh_web_token_api,{});C=B.handle_request_result_message('refresh_web_token_api',A)
if J in A and A[J]==H:D.accessToken=A[B][BS];D.refreshToken=A[B][Aa];return{C:0} if _H in A and A[_H]==_G:B.accessToken=A[_A][_B0];B.refreshToken=A[_A][_AI];return{_C:0}
return{C:1,i:E} return{_C:1,_g:C}
async def __get_door_number(E): async def __get_door_number(A):
H={D:F[D],G:F[G],V:F[V],M:{a:F[AE][M][a],d:F[AE][M][d],e:F[AE][M][e],b:F[AE][M][b]},A8:{U:E.userInfo[U]},r:E.token};A=await E.fetch(Aq,H);I=E.handle_request_result_message('get_door_number_api',A) B=configuration[_Ak];G={_B:B[_B],_E:B[_E],_P:B[_P],_J:{_V:B[_J][_V],_Y:B[_J][_Y],_Z:B[_J][_Z],_W:B[_J][_W]},_u:{_R:A.userInfo[_R]},_k:A.token};C=await A.__fetch_safe(get_door_number_api,G);H=A.handle_request_result_message('get_door_number_api',C)
if J in A and A[J]==1 and B in A and m in A[B]:E.powerUserList=A[B][m][B0];return{C:0} if _H in C and C[_H]==1 and _A in C and _l in C[_A]:
return{C:1,i:I} D={}
async def __get_door_balance(L,door_account): if A.powerUserList is not _F:D={A[_c]:A for A in A.powerUserList}
C=door_account;O={B:{N:A,Q:A,I:F[u][I],E:F[u][E],AA:L.userInfo[U],AB:L.userInfo[AI],W:H,h:H,Ac:L.userInfo[U],AC:[{BT:C[s],AJ:C[X],BU:C[B1],n:C[n],c:C[c]}]},D:As,G:F[G],V:C[X]};K=await L.fetch(AP,O);L.handle_request_result_message('get_door_balance_api',K) E=[]
if J in K and K[J]==1 and B in K and AC in K[B]: for F in C[_A][_l][_AU]:
M=K[B][AC] if F[_c]in D:E.append(D[F[_c]])
if t(M)!=0:C[AK]=M[0] else:E.append(F)
async def __get_door_bill(L,door_account,year): A.powerUserList=E;return{_C:0}
P='dataInfo';M='mothEleList';C=door_account;O={B:{N:A,Q:A,I:F[u][I],E:F[u][E],AA:L.userInfo[U],AB:L.userInfo[AI],W:H,h:H,Ac:L.userInfo[U],AC:[{BT:C[s],AJ:C[X],BU:C['consSortCode'],n:C[n],c:C[c]}]},D:As,G:F[G],V:C[X]};O={B:{AA:L.userInfo[U],I:F[I],l:'11',B2:C[B1],E:'ALIPAY_01',c:C[c],AJ:C[X],h:H,W:H,Q:A,N:A,AB:A,BV:C[X],Ac:L.userInfo[U],n:C[n],BW:year},D:A7,G:A6,V:C[X]};K=await L.fetch(AQ,O);L.handle_request_result_message('get_door_bill_api',K) return{_C:1,_g:H}
if J in K and K[J]==1 and B in K: async def __get_door_balance(B,door_account):
if P in K[B]:C[Ad]=K[B][P] A=door_account;E={_A:{_L:'',_N:'',_I:configuration[_A7][_I],_D:configuration[_A7][_D],_A2:B.userInfo[_R],_A3:B.userInfo.get(_AC,B.userInfo.get('nickname',_F)),_U:_G,_b:_G,_AV:B.userInfo[_R],_AB:[{'consNoSrc':A[_c],_AD:A.get(_X,A.get(_A4,_F)),'sceneType':A.get('consSortCode',A.get('elecTypeCode',_F)),_p:A[_p],_d:A[_d]}]},_B:'0101143',_E:configuration[_E],_P:A.get(_X,A.get(_A4,_F))};C=await B.__fetch_safe(get_door_balance_api,E);B.handle_request_result_message('get_door_balance_api',C)
if M in K[B]:C[AD]=K[B][M];C[Ae]=K[B][M][-1]['month'] if _H in C and C[_H]==1 and _A in C and _AB in C[_A]:
async def __get_door_ladder(H,door_account,month): D=C[_A][_AB]
O='ladder_flag';M=month;C=door_account;P=C[s];R={B:{I:F[v][I],E:F[v][E],W:F[v][W],l:F[v][l],n:C[s],h:C[X],c:C[c],'queryDate':M,BV:C[X],B2:C[B1],Ac:H.userInfo[U],Q:A,N:A,AB:H.userInfo[AI],AA:H.userInfo[U]},D:F[v][D],G:F[v][G],V:C[X]};K=await H.fetch(AR,R);S=H.handle_request_result_message('get_door_ladder_api',K) if len(D)!=0:A[_A5]=D[0]
if J in K and K[J]==1 and B in K and AC in K[B]: async def __get_door_bill(C,door_account,monthDate):
L=K[B][AC] I='dataInfo';G='mothEleList';E=monthDate;A=door_account;J={_A:{_A2:C.userInfo[_R],_I:configuration[_I],_f:'11',_AK:A[_B2],_D:'ALIPAY_01',_d:A[_d],_AD:A[_X],_b:_G,_U:_G,_N:'',_L:'',_A3:'',_B1:A[_X],_AV:C.userInfo[_R],_p:A[_p],_AW:E.year},_B:_A0,_E:_z,_P:A[_X]};B=await C.__fetch_safe(get_door_bill_api,J);C.handle_request_result_message('get_door_bill_api',B)
if t(L)!=0: if _H in B and B[_H]==1 and _A in B:
L=L[0];L['month']=M if I in B[_A]:A[_AL]=B[_A][I]
if L['electricParticulars']['levelFlag']=='2':C[O]=1 if G in B[_A]:
else:C[O]=0 if _AE not in A or A[_AE]!=E.year:A[_m]=B[_A][G];A[_AE]=E.year
H.doorAccountDict[P]['ladder']=L else:
async def __get_door_daily_bill(C,door_account,year,start_date,end_date): F={A.month:A for A in A[_m]};H=B[_A][G]
L='sevenEleList';K=door_account;O={BX:{D:F[D],G:F[G],V:F[V],M:{a:F[M][a],d:F[M][d],e:F[M][e],b:F[M][b]},A8:{U:C.userInfo[U]},r:C.token},BY:{B:{AA:C.userInfo[U],n:K[s],B2:g,'endTime':end_date,c:K[c],BW:year,AJ:K[X],Q:A,N:A,'startTime':start_date,AB:C.userInfo[AI],E:F[p][E],I:F[p][I],l:F[p][l],h:F[p][h],W:F[p][W]},D:F[p][D],G:F[p][G],V:K[X]},BZ:'010103'};H=await C.fetch(AT,O);P=C.handle_request_result_message('get_door_daily_bill_api',H) for D in H:
if J in H and H[J]==1 and B in H and L in H[B]:K[Y]=H[B][L] if D.month in F and _h in F[D.month]:D[_h]=F[D.month][_h]
async def __get_door_pay_record(C,door_account):J=door_account;L=J[s];K={BX:{D:F[D],G:F[G],V:F[V],M:{a:F[M][a],d:F[M][d],e:F[M][e],b:F[M][b]},A8:{U:C.userInfo[U]},r:C.token},BY:{B:{AA:C.userInfo[U],'bgnPayDate':'2023-04-24',I:F[I],n:J[s],'endPayDate':'2024-04-24',E:'webALIPAY_01','number':100,c:J[c],'page':H,AJ:J[X],h:H,W:H,Q:A,N:A,AB:C.userInfo[AI]},D:'0101051',G:g,V:J[X]},BZ:'010104'};O=await C.fetch(AS,K) A[_m]=H
if len(A[_m])>0:A[_v]=A[_m][-1]
async def __get_door_ladder(C,door_account,monthBill):
E=monthBill;A=door_account;I=A[_c];F=datetime.datetime.strptime(E[_AM],'%Y%m');G=f"{F.year}-{F.month:02d}";H={_A:{_I:configuration[_q][_I],_D:configuration[_q][_D],_U:configuration[_q][_U],_f:configuration[_q][_f],_p:A[_c],_b:A[_X],_d:A[_d],'queryDate':G,_B1:A[_X],_AK:A[_B2],_AV:C.userInfo[_R],_N:'',_L:'',_A3:C.userInfo[_AC],_A2:C.userInfo[_R]},_B:configuration[_q][_B],_E:configuration[_q][_E],_P:A[_X]};B=await C.__fetch(get_door_ladder_api,H);J=C.handle_request_result_message('get_door_ladder_api',B)
if _H in B and B[_H]==1 and _A in B and _AB in B[_A]:
D=B[_A][_AB]
if len(D)!=0:D=D[0];E['ladder']=D
async def __get_door_mouth_daily_bill(B,door_account,monthBill):
F=monthBill;A=door_account;N=A[_c];L=datetime.datetime.strptime(F[_AM],'%Y%m');M={_AX:{_B:configuration[_B],_E:configuration[_E],_P:configuration[_P],_J:{_V:configuration[_J][_V],_Y:configuration[_J][_Y],_Z:configuration[_J][_Z],_W:configuration[_J][_W]},_u:{_R:B.userInfo[_R]},_k:B.token},_AY:{_A:{_A2:B.userInfo[_R],_p:A[_c],_AK:_a,'endTime':F['endDate'],_d:A[_d],_AW:str(L.year),_AD:A.get(_X,A.get(_A4,_F)),_N:'',_L:'',_B3:F['begDate'],_A3:B.userInfo[_AC],_D:configuration[_T][_D],_I:configuration[_T][_I],_f:configuration[_T][_f],_b:configuration[_T][_b],_U:configuration[_T][_U]},_B:configuration[_T][_B],_E:configuration[_T][_E],_P:A.get(_X,A.get(_A4,_F))},_AZ:'010103'};C=await B.__fetch_safe(get_door_daily_bill_api,M);O=B.handle_request_result_message(_B4,C)
if _H in C and C[_H]==1 and _A in C and _AN in C[_A]:
G=0;H=0;I=0;J=0;K=0
for D in C[_A][_AN]:P=datetime.datetime.strptime(D['day'],_Aa);G+=catchFloat(D,_AO);H+=catchFloat(D,_Ab);I+=catchFloat(D,_Ac);J+=catchFloat(D,_Ad);K+=catchFloat(D,_Ae)
E={};E[_Af]=normal_round(G,2);E[_Ag]=normal_round(H,2);E[_Ah]=normal_round(I,2);E[_Ai]=normal_round(J,2);E[_Aj]=normal_round(K,2);F[_h]=E
async def __get_door_daily_bill(B,door_account,year,start_date,end_date):
A=door_account;D={_AX:{_B:configuration[_B],_E:configuration[_E],_P:configuration[_P],_J:{_V:configuration[_J][_V],_Y:configuration[_J][_Y],_Z:configuration[_J][_Z],_W:configuration[_J][_W]},_u:{_R:B.userInfo[_R]},_k:B.token},_AY:{_A:{_A2:B.userInfo[_R],_p:A[_c],_AK:_a,'endTime':end_date,_d:A[_d],_AW:year,_AD:A.get(_X,A.get(_A4,_F)),_N:'',_L:'',_B3:start_date,_A3:B.userInfo[_AC],_D:configuration[_T][_D],_I:configuration[_T][_I],_f:configuration[_T][_f],_b:configuration[_T][_b],_U:configuration[_T][_U]},_B:configuration[_T][_B],_E:configuration[_T][_E],_P:A.get(_X,A.get(_A4,_F))},_AZ:'010103'};C=await B.__fetch_safe(get_door_daily_bill_api,D);E=B.handle_request_result_message(_B4,C)
if _H in C and C[_H]==1 and _A in C and _AN in C[_A]:A[_A6]=C[_A][_AN]
async def __get_door_pay_record(A,door_account):B=door_account;D=B[_c];C={_AX:{_B:configuration[_B],_E:configuration[_E],_P:configuration[_P],_J:{_V:configuration[_J][_V],_Y:configuration[_J][_Y],_Z:configuration[_J][_Z],_W:configuration[_J][_W]},_u:{_R:A.userInfo[_R]},_k:A.token},_AY:{_A:{_A2:A.userInfo[_R],'bgnPayDate':'2023-04-24',_I:configuration[_I],_p:B[_c],'endPayDate':'2024-04-24',_D:'webALIPAY_01','number':100,_d:B[_d],'page':_G,_AD:B[_X],_b:_G,_U:_G,_N:'',_L:'',_A3:A.userInfo[_AC]},_B:'0101051',_E:_a,_P:B[_X]},_AZ:'010104'};E=await A.__fetch(getJiaoFeiRecordApi,C)
async def get_qr_code(B): async def get_qr_code(B):
A=await B.__get_request_key() A=await B.__get_request_key()
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
return await B.__get_qr_code() return await B.__get_qr_code()
async def check_qr_code(B): async def check_qr_code(B):
A=await B.__get_qr_code_status() A=await B.__get_qr_code_status()
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
A=await B.__get_qr_code_token() A=await B.__get_qr_code_token()
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
return await B.__get_token() return await B.__get_token()
async def send_phone_code(B,phone): async def send_phone_code(B,phone):
A=await B.__get_request_key() A=await B.__get_request_key()
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
return await B.__send_code(phone) return await B.__send_code(phone)
async def verfiy_phone_code(B,code): async def verfiy_phone_code(B,code):
A=await B.__verfiy_code(code) A=await B.__verfiy_code(code)
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
return await B.__get_token() return await B.__get_token()
async def __get_token(D): async def __get_token(B):
A=await D.__get_request_key() A=await B.__get_request_key()
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
A=await D.__get_request_authorize() A=await B.__get_request_authorize()
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
A=await D.__get_web_token() A=await B.__get_web_token()
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
A=await D.__get_door_number() A=await B.__get_door_number()
if C in A and A[C]!=0:return A if _C in A and A[_C]!=0:return A
D.need_login=z;await D.save_data();return{C:0,B:D.powerUserList} B.need_login=_i;await B.save_data();return{_C:0,_A:B.powerUserList}
async def refresh_data(B,setup=z): async def __refresh_token(A):
q='daily_t_ele_num';p='daily_n_ele_num';o='daily_v_ele_num';n='daily_p_ele_num';m='daily_ele_num';l='last_month_ele_cost';k='last_month_ele_num';i='year_ele_cost';h='year_ele_num';g='monthEleNum';f='thisTPq';e='thisNPq';d='thisVPq';c='thisPPq';T='balance';S='ladder_level_num';R='ladder_level';L='%Y%m%d';K='day';I='dayElePq';r=setup or int(Af.time()*1000)-B.timestamp>B.refresh_interval*3600*1000 B=await A.__get_request_key()
if r is z:return if _C in B and B[_C]!=0:return
E=await B.__get_door_number() B=await A.__refresh_web_token()
if C in E and E[C]!=0: if _C in B and B[_C]==0:A.need_login=_i;A.retry_times=0;await A.save_data()
A0.warning('刷新 Token');E=await B.__get_request_key() elif A.retry_times>=3:A.need_login=_o
if C in E and E[C]!=0:return else:A.retry_times=A.retry_times+1
E=await B.__refresh_web_token() async def refresh_data(B,setup=_i,force_refresh=_i):
if C in E and E[C]==0:await B.save_data() p='last_month_ele_cost';o='year_ele_cost';n='%Y-%m-%d %H:%M:%S';b=setup;a='last_month_ele_num';Z='daily_lasted_date';Y='refresh_time';U='year_ele_num';G='balance'
else:B.need_login=AW;A0.error('刷新 Token 失败');return if b is _o:
E=await B.__get_door_number() if B.dataVersion!=VERSION:B.powerUserList=_F
if C in E and E[C]!=0:B.need_login=AW;A0.error('重新请求失败');return c=await B.__get_door_number()
M=j.datetime.now();J=M-j.timedelta(days=1);u=f"{J.year}-{J.month:02d}-{J.day:02d}";N=J-j.timedelta(days=40);v=f"{N.year}-{N.month:02d}-{N.day:02d}" if _C in c and c[_C]!=0:B.need_login=_o
if B.need_login is _o:
if B.powerUserList is not _F:
for A in B.get_door_account_list():A[Y]='Token刷新失败,请重新登录'
LOGGER.error('国家电网 - Token刷新失败,请重新登录!');return
q=b or force_refresh or int(time.time()*1000)-B.timestamp>B.refresh_interval*3600*1000
if q is _i:return
H=datetime.datetime.now();F=H-datetime.timedelta(days=1);d=f"{F.year}-{F.month:02d}-{F.day:02d}";V=F-datetime.timedelta(days=40);r=f"{V.year}-{V.month:02d}-{V.day:02d}"
for A in B.powerUserList: for A in B.powerUserList:
w=A[s];B.doorAccountDict[w]=A;await B.__get_door_balance(A);await B.__get_door_daily_bill(A,M.year,v,u);O=A[Y][0] s=A[_c];B.doorAccountDict[s]=A
try:float(O[I]) if Z in A and A[Z]==d:A[Y]=datetime.datetime.strftime(H,n);continue
except:A[Y].pop(0) await B.__get_door_balance(A)
O=A[Y][0];F=j.datetime.strptime(O[K],L);U=0;V=0;W=0;X=0;Z=0 if B.retry_times!=0:return
for D in A[Y]: if _A5 in A:
H=j.datetime.strptime(D[K],L) t=catchFloat(A[_A5],'estiAmt');W=catchFloat(A[_A5],'prepayBal');e=catchFloat(A[_A5],'sumMoney')
if H.month!=F.month:break if W==0 or W==e:A[G]=e
U+=P(D,I);V+=P(D,c);W+=P(D,d);X+=P(D,e);Z+=P(D,f) else:A[G]=W-t
Q=F-j.timedelta(days=F.day);a=f"{Q.year}-{Q.month:02d}" f=catchFloat(A[_A5],'historyOwe')
if Ae not in A or A[Ae]!=a:await B.__get_door_bill(A,Q.year);await B.__get_door_ladder(A,a) if f>0:A[G]=-f
x=j.datetime.strptime(A[Ae],'%Y%m') else:LOGGER.error('国家电网账户余额获取失败!')
if x.month==12: if G not in A:A[G]=0
G=0 await B.__get_door_daily_bill(A,H.year,r,d)
for D in A[Y]: if _A6 not in A:LOGGER.error('国家电网无法获取日用电数据!');return
H=j.datetime.strptime(D[K],L) X=0;I=_i
if H.month!=12:break for g in range(10):
G+=P(D,I) D=A[_A6][g]
try:float(D[_AO]);I=_o;break
except:X=X+1
h=0;i=0;j=0;k=0;l=0
if I:
for g in range(X):A[_A6].pop(0)
D=A[_A6][0];E=datetime.datetime.strptime(D['day'],_Aa);A[Z]=f"{E.year}-{E.month:02d}-{E.day:02d}";h=catchFloat(D,_AO);i=catchFloat(D,_Ab);j=catchFloat(D,_Ac);k=catchFloat(D,_Ad);l=catchFloat(D,_Ae)
A['daily_ele_num']=normal_round(h,2);A['daily_p_ele_num']=normal_round(i,2);A['daily_v_ele_num']=normal_round(j,2);A['daily_n_ele_num']=normal_round(k,2);A['daily_t_ele_num']=normal_round(l,2);J=0;K=0;L=0;M=0;N=0
if I:
for C in A[_A6]:
u=datetime.datetime.strptime(C['day'],_Aa)
if u.month!=E.month:break
J+=catchFloat(C,_AO);K+=catchFloat(C,_Ab);L+=catchFloat(C,_Ac);M+=catchFloat(C,_Ad);N+=catchFloat(C,_Ae)
A[_Af]=normal_round(J,2);A[_Ag]=normal_round(K,2);A[_Ah]=normal_round(L,2);A[_Ai]=normal_round(M,2);A[_Aj]=normal_round(N,2)
if I:
O=E-datetime.timedelta(days=E.day);v=f"{O.year}{O.month:02d}"
if _AE not in A or A[_AE]!=O.year or _v not in A or A[_v][_AM]!=v:await B.__get_door_bill(A,O)
if _m in A:
for C in A[_m]:
if _h not in C:await B.__get_door_mouth_daily_bill(A,C)
if _AL in A:A[U]=catchFloat(A[_AL],'totalEleNum');A[o]=catchFloat(A[_AL],'totalEleCost')
if U not in A:A[U]=0;A[o]=0
if _v in A:A[a]=catchFloat(A[_v],'monthEleNum');A[p]=catchFloat(A[_v],'monthEleCost');m=datetime.datetime.strptime(A[_v][_AM],'%Y%m')
if a not in A:A[a]=0;A[p]=0;m=F.month
P=0;Q=0;R=0;S=0;T=0
if m.month==12:P=J;Q=K;R=L;S=M;T=N
else: else:
G=0 if _m in A:
for D in A[AD]:G+=P(D,g) for C in A[_m]:
y=t(A[AD]) if _h in C:P+=C[_h][_Af];Q+=C[_h][_Ag];R+=C[_h][_Ah];S+=C[_h][_Ai];T+=C[_h][_Aj]
for D in A[Y]: P+=J;Q+=K;R+=L;S+=M;T+=N
H=j.datetime.strptime(D[K],L) A[U]=normal_round(P,2);A['year_p_ele_num']=normal_round(Q,2);A['year_v_ele_num']=normal_round(R,2);A['year_n_ele_num']=normal_round(S,2);A['year_t_ele_num']=normal_round(T,2);A[Y]=datetime.datetime.strftime(H,n)
if H.month<=y:break
G+=P(D,I)
if G<=2760:A[R]='第一阶梯';A[S]=1
elif G<=4800:A[R]='第二阶梯';A[S]=2
else:A[R]='第三阶梯';A[S]=3
if AK in A:
A1=P(A[AK],'estiAmt');A2=P(A[AK],'prepayBal');A[T]=A2-A1;b=P(A[AK],'historyOwe')
if b>0:A[T]=-b
else:A[T]=0
if Ad in A:A[h]=P(A[Ad],'totalEleNum');A[i]=P(A[Ad],'totalEleCost')
else:A[h]=0;A[i]=0
if AD in A:A[k]=P(A[AD][-1],g);A[l]=P(A[AD][-1],'monthEleCost')
else:A[k]=0;A[l]=0
if Y in A:A[m]=P(A[Y][0],I);A[n]=P(A[Y][0],c);A[o]=P(A[Y][0],d);A[p]=P(A[Y][0],e);A[q]=P(A[Y][0],f)
else:A[m]=0;A[n]=0;A[o]=0;A[p]=0;A[q]=0
A['month_ele_num']=U;A['month_p_ele_num']=V;A['month_v_ele_num']=W;A['month_n_ele_num']=X;A['month_t_ele_num']=Z;A['daily_lasted_date']=f"{F.year}-{F.month:02d}-{F.day:02d}";A['refresh_time']=j.datetime.strftime(M,'%Y-%m-%d %H:%M:%S')
await B.save_data() await B.save_data()
async def get_door_account_list(A):return list(A.doorAccountDict.values()) def get_door_account_list(A):return list(A.doorAccountDict.values())
def get_door_account(A):return A.doorAccountDict def get_door_account(A):return A.doorAccountDict
+2 -2
View File
@@ -3,7 +3,7 @@
"name": "国家电网", "name": "国家电网",
"codeowners": ["@hassbox"], "codeowners": ["@hassbox"],
"config_flow": true, "config_flow": true,
"documentation": "https://github.com/hass-box/state-grid", "documentation": "https://hassbox.cn/",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"version": "0.0.4" "version": "0.1.3"
} }
+172 -137
View File
@@ -2,13 +2,11 @@ from homeassistant.components.sensor import (
DOMAIN as SENSOR_DOMAIN, DOMAIN as SENSOR_DOMAIN,
SensorDeviceClass, SensorDeviceClass,
SensorEntity, SensorEntity,
SensorEntityDescription,
SensorStateClass, SensorStateClass,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfEnergy from homeassistant.const import UnitOfEnergy
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
@@ -18,132 +16,160 @@ from .const import DOMAIN, VERSION
from .data_client import StateGridDataClient from .data_client import StateGridDataClient
from .coordinator import StateGridCoordinator from .coordinator import StateGridCoordinator
CURRENCY_YUAN = "" UNIT_YUAN = ""
ENTITY_ID_SENSOR_FORMAT = SENSOR_DOMAIN + ".state_grid_" ENTITY_ID_SENSOR_FORMAT = SENSOR_DOMAIN + ".state_grid_"
SENSOR_TYPES = ( SENSOR_TYPES = [
SensorEntityDescription( {
key="balance", "key":"balance",
translation_key="balance", "name": "账户余额",
native_unit_of_measurement=CURRENCY_YUAN, "native_unit_of_measurement": UNIT_YUAN,
device_class=SensorDeviceClass.MONETARY, "device_class": SensorDeviceClass.MONETARY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="year_ele_num", "key": "year_ele_num",
translation_key="year_ele_num", "name": "年度累计用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="year_ele_cost", "key": "year_p_ele_num",
translation_key="year_ele_cost", "name": "年度累计峰用电",
native_unit_of_measurement=CURRENCY_YUAN, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.MONETARY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="last_month_ele_num", "key": "year_v_ele_num",
translation_key="last_month_ele_num", "name": "年度累计谷用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="last_month_ele_cost", "key": "year_n_ele_num",
translation_key="last_month_ele_cost", "name": "年度累计平用电",
native_unit_of_measurement=CURRENCY_YUAN, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.MONETARY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="month_ele_num", "key": "year_t_ele_num",
translation_key="month_ele_num", "name": "年度累计尖用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="month_p_ele_num", "key": "year_ele_cost",
translation_key="month_p_ele_num", "name": "年度累计电费",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UNIT_YUAN,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.MONETARY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="month_v_ele_num", "key": "last_month_ele_num",
translation_key="month_v_ele_num", "name": "上个月用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="month_n_ele_num", "key": "last_month_ele_cost",
translation_key="month_n_ele_num", "name": "上个月电费",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UNIT_YUAN,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.MONETARY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="month_t_ele_num", "key": "month_ele_num",
translation_key="month_t_ele_num", "name": "当月累计用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="daily_ele_num", "key": "month_p_ele_num",
translation_key="daily_ele_num", "name": "当月累计峰用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="daily_p_ele_num", "key": "month_v_ele_num",
translation_key="daily_p_ele_num", "name": "当月累计谷用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="daily_v_ele_num", "key": "month_n_ele_num",
translation_key="daily_v_ele_num", "name": "当月累计平用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="daily_n_ele_num", "key": "month_t_ele_num",
translation_key="daily_n_ele_num", "name": "当月累计尖用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="daily_t_ele_num", "key": "daily_ele_num",
translation_key="daily_t_ele_num", "name": "日总用电",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY, "device_class": SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL "state_class": SensorStateClass.TOTAL
), },
SensorEntityDescription( {
key="daily_lasted_date", "key": "daily_p_ele_num",
translation_key="daily_lasted_date" "name": "日峰用电",
), "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
SensorEntityDescription( "device_class": SensorDeviceClass.ENERGY,
key="refresh_time", "state_class": SensorStateClass.TOTAL
translation_key="refresh_time" },
) {
) "key": "daily_v_ele_num",
"name": "日谷用电",
"native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
},
{
"key": "daily_n_ele_num",
"name": "日平用电",
"native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
},
{
"key": "daily_t_ele_num",
"name": "日尖用电",
"native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
},
{
"key": "daily_lasted_date",
"name": "最新日用电日期"
},
{
"key": "refresh_time",
"name": "最近刷新时间"
}
]
SENSOR_TYPES_FOR_LADDER = ( SENSOR_TYPES_FOR_LADDER = [
SensorEntityDescription( {
key="ladder_level", "key": "ladder_level",
translation_key="ladder_level" "name": "当前阶梯"
), },
) ]
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
@@ -151,42 +177,51 @@ async def async_setup_entry(
coordinator = StateGridCoordinator(hass) coordinator = StateGridCoordinator(hass)
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
data_client: StateGridDataClient = hass.data[DOMAIN] data_client: StateGridDataClient = hass.data[DOMAIN]
door_account_list = await data_client.get_door_account_list() door_account_list = data_client.get_door_account_list()
for door_account in door_account_list: for door_account in door_account_list:
async_add_entities( async_add_entities(
[StateGridSensor(door_account, description, entry.entry_id, coordinator) for description in SENSOR_TYPES] [StateGridSensor(door_account, sensor_type, entry.entry_id, coordinator) for sensor_type in SENSOR_TYPES]
) )
# if door_account["ladder_flag"] == 1: # if door_account["ladder_flag"] == 1:
# async_add_entities( # async_add_entities(
# StateGridSensor(door_account, description, entry.entry_id) # StateGridSensor(door_account, sensor_type, entry.entry_id)
# for description in SENSOR_TYPES_FOR_LADDER # for sensor_type in SENSOR_TYPES_FOR_LADDER
# ) # )
class StateGridSensor(CoordinatorEntity[StateGridCoordinator], SensorEntity): class StateGridSensor(CoordinatorEntity[StateGridCoordinator], SensorEntity):
_attr_has_entity_name = True _attr_has_entity_name = True
entity_description: SensorEntityDescription
def __init__( def __init__(
self, door_account, entity_description: SensorEntityDescription, entry_id: str, coordinator: StateGridCoordinator, self, door_account, sensor_type, entry_id: str, coordinator: StateGridCoordinator,
) -> None: ) -> None:
super().__init__(coordinator) super().__init__(coordinator)
self.entity_description = entity_description
self.door_account = door_account self.door_account = door_account
self.entity_id = SENSOR_DOMAIN + ".state_grid" + "_" + door_account["consNo_dst"] + "_" + entity_description.key self.sensor_type = sensor_type
self._attr_translation_key = entity_description.key self.entity_id = SENSOR_DOMAIN + ".state_grid" + "_" + door_account["consNo_dst"] + "_" + sensor_type["key"]
self._attr_unique_id = entry_id + "-" + door_account["consNo_dst"] + "-" + entity_description.key self._attr_name = sensor_type["name"]
self._attr_unique_id = entry_id + "-" + door_account["consNo_dst"] + "-" + sensor_type["key"]
if "device_class" in sensor_type:
self._attr_device_class = sensor_type["device_class"]
if "state_class" in sensor_type:
self._attr_state_class = sensor_type["state_class"]
if "native_unit_of_measurement" in sensor_type:
self._attr_native_unit_of_measurement = sensor_type["native_unit_of_measurement"]
self._attr_device_info = { self._attr_device_info = {
"name": door_account["elecAddr_dst"], "name": door_account["elecAddr_dst"],
"identifiers": {(DOMAIN, door_account["consNo_dst"])}, "identifiers": {(DOMAIN, door_account["consNo_dst"])},
"sw_version": VERSION, "sw_version": VERSION,
"manufacturer": "HassBox", "manufacturer": "HassBox",
"model": "户号:" + door_account["consName_dst"] + " - " + door_account["consNo_dst"], "model": "户号:" + door_account["consName_dst"] + " - " + door_account["consNo_dst"]
"entry_type": DeviceEntryType.SERVICE,
} }
@property @property
def native_value(self): def native_value(self):
data = self.coordinator.data[self.door_account["consNo_dst"]] data = self.coordinator.data[self.door_account["consNo_dst"]]
return data[self.entity_description.key] return data[self.sensor_type["key"]]
-58
View File
@@ -70,63 +70,5 @@
"get_qr_code_error": "{errmsg}", "get_qr_code_error": "{errmsg}",
"check_qr_code_error": "{errmsg}" "check_qr_code_error": "{errmsg}"
} }
},
"entity": {
"sensor": {
"balance": {
"name": "账户余额"
},
"year_ele_num": {
"name": "年度累计用电"
},
"year_ele_cost": {
"name": "年度累计电费"
},
"last_month_ele_num": {
"name": "上个月用电"
},
"last_month_ele_cost": {
"name": "上个月电费"
},
"month_ele_num": {
"name": "当月累计用电"
},
"month_p_ele_num": {
"name": "当月累计峰用电"
},
"month_v_ele_num": {
"name": "当月累计谷用电"
},
"month_n_ele_num": {
"name": "当月累计平用电"
},
"month_t_ele_num": {
"name": "当月累计尖用电"
},
"daily_ele_num": {
"name": "日总用电"
},
"daily_p_ele_num": {
"name": "日峰用电"
},
"daily_v_ele_num": {
"name": "日谷用电"
},
"daily_n_ele_num": {
"name": "日平用电"
},
"daily_t_ele_num": {
"name": "日尖用电"
},
"daily_lasted_date": {
"name": "最新日用电日期"
},
"ladder_level": {
"name": "当前阶梯"
},
"refresh_time": {
"name": "最近刷新时间"
}
}
} }
} }
@@ -0,0 +1,74 @@
{
"config": {
"flow_title": "国家电网",
"step": {
"user": {
"title": "国家电网",
"description": "集成国家电网可以选择网上国网 App 扫码登录或短信验证码登录。如登录异常,可至 **HassBox全屋智能** 微信公众号联系客服。"
},
"code_login": {
"title": "短信验证码登录",
"description": "手机号需先在网上电网 App 注册并绑定户号",
"data": {
"phone": "请输入手机号"
}
},
"verfiy_code": {
"title": "短信验证码登录",
"data": {
"code": "请输入验证码"
}
},
"check_qr_code": {
"title": "网上国网 App 扫码登录",
"description": "\n {qr_image} \n\n\n 请使用 网上国网 App 扫码登录,确认登录后再点击提交。"
}
},
"abort": {
"single_instance_allowed": "该集成已经配置过了,且只能配置一次。若要重新配置,请先删除旧集成。",
"get_qr_code_error": "{errmsg}",
"check_qr_code_error": "{errmsg}"
}
},
"options": {
"step": {
"debug": {
"title": "国家电网",
"description": "国家电网当日用电等数据一般隔天才会刷新,且各地区时间不一,可根据情况适当调整接口轮询间隔。",
"data": {
"refresh_interval": "轮询间隔",
"is_debug": "调试模式"
},
"data_description": {
"is_debug": "打开调试开关后,将会打印所有请求日志。可在[配置]-[系统]-[日志]中查看。\n如需反馈异常,可至 **HassBox全屋智能** 微信公众号联系客服。"
}
},
"user": {
"title": "重新登录国家电网",
"description": "刷新 Token 异常,需重新登录。\n如需反馈异常,可至 **HassBox全屋智能** 微信公众号联系客服。"
},
"code_login": {
"title": "短信验证码登录",
"description": "手机号需先在网上电网 App 注册并绑定户号",
"data": {
"phone": "请输入手机号"
}
},
"verfiy_code": {
"title": "短信验证码登录",
"data": {
"code": "请输入验证码"
}
},
"check_qr_code": {
"title": "网上国网 App 扫码登录",
"description": "\n {qr_image} \n\n\n 请使用 网上国网 App 扫码登录,确认登录后再点击提交。"
}
},
"abort": {
"single_instance_allowed": "该集成已经配置过了,且只能配置一次。若要重新配置,请先删除旧集成。",
"get_qr_code_error": "{errmsg}",
"check_qr_code_error": "{errmsg}"
}
}
}
@@ -70,63 +70,5 @@
"get_qr_code_error": "{errmsg}", "get_qr_code_error": "{errmsg}",
"check_qr_code_error": "{errmsg}" "check_qr_code_error": "{errmsg}"
} }
},
"entity": {
"sensor": {
"balance": {
"name": "账户余额"
},
"year_ele_num": {
"name": "年度累计用电"
},
"year_ele_cost": {
"name": "年度累计电费"
},
"last_month_ele_num": {
"name": "上个月用电"
},
"last_month_ele_cost": {
"name": "上个月电费"
},
"month_ele_num": {
"name": "当月累计用电"
},
"month_p_ele_num": {
"name": "当月累计峰用电"
},
"month_v_ele_num": {
"name": "当月累计谷用电"
},
"month_n_ele_num": {
"name": "当月累计平用电"
},
"month_t_ele_num": {
"name": "当月累计尖用电"
},
"daily_ele_num": {
"name": "日总用电"
},
"daily_p_ele_num": {
"name": "日峰用电"
},
"daily_v_ele_num": {
"name": "日谷用电"
},
"daily_n_ele_num": {
"name": "日平用电"
},
"daily_t_ele_num": {
"name": "日尖用电"
},
"daily_lasted_date": {
"name": "最新日用电日期"
},
"ladder_level": {
"name": "当前阶梯"
},
"refresh_time": {
"name": "最近刷新时间"
}
}
} }
} }
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB