2 Commits
Author SHA1 Message Date
zimonianhua 47b46be217 添加HACS文件 2024-07-30 13:42:01 +08:00
EastWood Yang c1db6b30b0 deploy 2024-07-26 16:55:43 +08:00
10 changed files with 369 additions and 366 deletions
Vendored
BIN
View File
Binary file not shown.
+4 -26
View File
@@ -1,29 +1,7 @@
# 国家电网 # State Grid
集成国家电网每日用电等数据,支持多户号,阶梯用电。 问题反馈可至 HassBox 小程序联系客服
## 安装/更新 或 入群反馈(本群仅用于国家电网集成问题反馈,严禁其他话题,违者❎)
#### 方法 1: 通过`Samba`或`SFTP`手动安装 ![image](https://github.com/user-attachments/assets/4f6d3d54-0948-4e44-8465-e3751e846b40)
下载并复制`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)
+1 -3
View File
@@ -11,7 +11,5 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
"""Set up this integration using UI.""" """Set up this integration using UI."""
config = await async_load_from_store(hass, "state_grid.config") or None config = await async_load_from_store(hass, "state_grid.config") or None
hass.data[DOMAIN] = StateGridDataClient(hass = hass, config = config) hass.data[DOMAIN] = StateGridDataClient(hass = hass, config = config)
hass.async_create_task( await hass.config_entries.async_forward_entry_setups(config_entry, [Platform.SENSOR])
hass.config_entries.async_forward_entry_setup(config_entry, Platform.SENSOR)
)
return True return True
+4 -2
View File
@@ -202,13 +202,13 @@ 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)
await self.data_client.coordinator.async_request_refresh()
return self.async_create_entry( return self.async_create_entry(
title="国家电网", title="国家电网",
data={} data={}
@@ -248,6 +248,8 @@ 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)
await self.data_client.coordinator.async_request_refresh()
return self.async_create_entry( return self.async_create_entry(
title="国家电网", title="国家电网",
data={} data={}
+1 -1
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.8" VERSION = "0.1.9"
VERSION_STORAGE = 1 VERSION_STORAGE = 1
+268 -222
View File
@@ -1,108 +1,120 @@
_Al='constType' _Aw='get_door_ladder_api'
_Ak='queryYear' _Av='queryDate'
_Aj='provinceCode' _Au='queryYear'
_Ai='access_token' _At='access_token'
_Ah='businessType' _As='businessType'
_Ag='qrCodeSerial' _Ar='qrCodeSerial'
_Af='redirect_url' _Aq='redirect_url'
_Ae='_access_token' _Ap='_access_token'
_Ad='refresh_interval' _Ao='dataVersion'
_Ac='doorAccountDict' _An='refresh_interval'
_Ab='refreshToken' _Am='doorAccountDict'
_Aa='accessToken' _Al='refreshToken'
_AZ='/osg-web0004/member/c24/f01' _Ak='accessToken'
_AY='BCP_00026' _Aj='/osg-web0004/member/c24/f01'
_AX='serviceCode_smt' _Ai='BCP_00026'
_AW='WEBA10070900' _Ah='serviceCode_smt'
_AV='serviceType' _Ag='WEBA10070900'
_AU='jM_custType' _Af='serviceType'
_AT='jM_busiTypeCode' _Ae='jM_custType'
_AS='doorNumberManeger' _Ad='jM_busiTypeCode'
_AR='month' _Ac='doorNumberManeger'
_AQ='consType' _Ab='month_t_ele_num'
_AP='userAccountId' _Aa='month_n_ele_num'
_AO='powerUserList' _AZ='month_v_ele_num'
_AN='publicKey' _AY='month_p_ele_num'
_AM='WEBA10070800' _AX='month_ele_num'
_AL='timeDay' _AW='constType'
_AK='WEBA10070700' _AV='provinceCode'
_AJ='channelNo' _AU='elecTypeCode'
_AI='monthBillList' _AT='powerUserList'
_AH='yearTotalCost' _AS='publicKey'
_AG='provinceId' _AR='WEBA10070800'
_AF='proCode' _AQ='timeDay'
_AE='loginAccount' _AP='WEBA10070700'
_AD='0000' _AO='channelNo'
_AC='refresh_token' _AN='month'
_AB='skey' _AM='yearTotalCost'
_AA='userInfo' _AL='consType'
_A9='0101046' _AK='provinceId'
_A8='list' _AJ='proCode'
_A7='userName' _AI='userAccountId'
_A6='acctId' _AH='0000'
_A5='keyCode' _AG='refresh_token'
_A4='querytypeCode' _AF='skey'
_A3='01010049' _AE='userInfo'
_A2='account' _AD='0101046'
_A1='account_balance' _AC='billYear'
_A0='resultCode' _AB='loginAccount'
_z='quInfo' _AA='keyCode'
_y=True _A9='querytypeCode'
_x='BCP_000026' _A8='01010049'
_w='app' _A7='account'
_v='WEBALIPAY_01' _A6='daily_bill_list'
_u='order' _A5='userName'
_t='state_grid' _A4='acctId'
_s='latestBillMonth' _A3='resultCode'
_r='consNo_dst' _A2='quInfo'
_A1='BCP_000026'
_A0='app'
_z='WEBALIPAY_01'
_y='order'
_x='state_grid'
_w='latestBillMonth'
_v='account_balance'
_u='list'
_t='authFlag'
_s='09'
_r='0101183'
_q='consNo' _q='consNo'
_p='authFlag' _p='token'
_o='09' _o=True
_n='0101183' _n='0101154'
_m='stepelect' _m='getday'
_l='daily_bill_list' _l='monthBillList'
_k='token' _k='bizrt'
_j=False _j='timestamp'
_i='0101154' _i=False
_h='getday' _h='month_ele'
_g='bizrt' _g='consNo_dst'
_f='clearCache' _f='errmsg'
_e='orgNo' _e='clearCache'
_d='timestamp' _d='promotCode'
_c='promotCode' _c='01'
_b='errmsg' _b='SGAPP'
_a='01' _a='devciceId'
_Z='SGAPP' _Z='devciceIp'
_Y='devciceId' _Y='orgNo'
_X='devciceIp' _X='tenant'
_W='proNo' _W='member'
_V='tenant' _V='stepelect'
_U='member' _U='proNo'
_T='promotType' _T='promotType'
_S='userId' _S='target'
_R='target' _R='userId'
_Q='srvrt' _Q='srvrt'
_P='subBusiTypeCode' _P='subBusiTypeCode'
_O='serialNo' _O='serCat'
_N='serCat' _N='serialNo'
_M='srvCode' _M='0902'
_L='0902' _L='srvCode'
_K='uscInfo' _K='uscInfo'
_J='busiTypeCode' _J='busiTypeCode'
_I='channelCode' _I='channelCode'
_H='code' _H='code'
_G=None _G='1'
_F='1' _F=None
_E='source' _E='source'
_D='funcCode' _D='funcCode'
_C='serviceCode' _C='serviceCode'
_B='errcode' _B='errcode'
_A='data' _A='data'
import json,time,aiohttp,urllib.parse,datetime import json,time,aiohttp,urllib.parse,datetime
from.const import VERSION
from.utils.logger import LOGGER from.utils.logger import LOGGER
from.utils.store import async_save_to_store from.utils.store import async_save_to_store
from.utils.crypt import a,b,c,d,e from.utils.crypt import a,b,c,d,e
configuration={_K:{_U:_L,_X:'',_Y:'',_V:_t},_E:_Z,_R:'32101',_I:_L,_AJ:_L,'toPublish':_a,'siteId':'2012000000033700',_M:'',_O:'',_D:'',_C:{_u:_i,'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:_L},'subscriptionList':{_M:'APP_SGPMS_05_030',_O:'22',_I:_L,_D:'22',_R:'-1'},'userInformation':{_C:'01008183',_E:_Z},'userInform':{_C:_n,_E:_Z},'elesum':{_I:_L,_D:_v,_c:_F,_T:_F,_C:'0101143',_E:_w},_A2:{_I:_L,_D:'WEBA1007200'},_AS:{_E:_L,_R:'-1',_I:_o,_AJ:_o,_C:_A3,_D:'WEBA40050000',_K:{_U:_L,_X:'',_Y:'',_V:_t}},'doorAuth':{_E:_Z,_C:'f04'},'xinZ':{_N:'101',_AT:'101','fJ_busiTypeCode':'102',_AU:'03','fJ_custType':'02',_AV:_a,_P:'',_D:_AK,_u:_i,_E:_Z,_A4:_F},'onedo':{_C:_A9,_E:_Z,_D:_AK,'queryType':'03'},'xinHuTongDian':{_N:'110',_J:'211',_P:'21102',_D:'WEBA10071200',_I:_L,_E:_o,_C:_n},'company':{_N:'104',_D:_AK,_AV:'02',_A4:_F,_p:_F,_E:_Z,_u:_i},'charge':{_I:_o,_D:'WEBA10071300',_AJ:'0901',_N:'102',_AU:_a,_AT:'102'},'other':{_I:_o,_D:'WEBA10079700',_N:'129',_J:'999',_P:'21501',_C:_x,_M:'',_O:''},'vatchange':{'submit':'0101003',_J:'320',_P:'',_N:'115',_D:'WEBA10074000',_p:_F},'bill':{_f:_F,_D:_v,_T:_F,_C:_x},_m:{_I:_L,_D:_v,_T:_F,_f:_o,_C:_x,_E:_w},_h:{_I:_L,_f:'11',_D:_v,_c:_F,_T:_F,_C:_x,_E:_w},'mouthOut':{_I:_L,_f:'11',_D:_v,_c:_F,_T:_F,_C:_x,_E:_w},'meter':{_N:'114',_J:'304',_D:'WEBA10071000',_P:'',_C:_A9,_O:''},'complaint':{_J:'005','srvMode':_L,'anonymousFlag':'0','replyMode':_a,'retvisitFlag':_a},'report':{_J:'006'},'tradewinds':{_J:'019'},'somesay':{_J:'091'},'faultrepair':{_D:_AW,_C:_n,_N:'111',_J:'001',_P:'21505'},'electronicInvoice':{_N:'105',_J:'0'},'rename':{_C:_A9,_D:'WEBA10076100',_J:'210',_N:'109',_p:_F,'gh_busiTypeCode':'211','gh_subusi':'21101',_O:'',_M:''},'pause':{_P:'',_C:_A3,_D:'WEBA10073600',_N:'107',_J:'203','jr_busi':'201',_O:'',_M:''},'capacityRecovery':{_C:_A3,_E:_Z,_M:'',_O:'',_D:'WEBA10073700','busiTypeCode_stop':'204','busiTypeCode_less':'202',_J:'202',_P:'',_N:'108',_AL:'5',_p:_F},'electricityPriceChange':{_C:_n,_J:'215',_P:'21502',_N:'113',_p:_F,_AL:'15',_D:'WEBA10073900WEB',_M:'',_O:''},'electricityPriceStrategyChange':{_C:'01008183',_J:'215',_P:'21506',_N:'160',_D:'WEBV00000517WEB',_M:'',_O:''},'eemandValueAdjustment':{_C:_n,_M:'',_O:'',_N:'112',_D:'WEBA10073800',_J:'215',_P:'21504',_p:_F,_AL:'5','getMonthServiceCode':_A9},'businessProgress':{_C:_n,_M:_a,_D:'WEB01'},'increase':{_E:_Z,_O:'',_M:'',_AX:_A3,_C:_i,_u:_i,_D:_AM,_A4:_F,_N:'106',_J:'111',_P:''},'fjincrea':{_N:'105',_J:'110',_P:'',_E:_Z,_D:_AM,_O:'',_M:'',_AX:_A3,_C:_i,_u:_i,_A4:_F},'persIncrea':{_N:'105',_J:'109',_u:_i,_P:'',_E:_Z,_D:_AM,_A4:_F},'fgdChange':{_C:_n,_M:_a,_I:_o,_D:_AW,_J:'215',_P:'21505',_N:'111',_p:_F},'createOrder':{_I:_L,_D:_v,_M:'BCP_000001','chargeMode':'02','conType':_a,'bizTypeId':'BT_ELEC'},'largePopulation':{_J:'383',_D:'WEBA10076800',_P:'',_M:'',_T:'',_c:'',_I:'0901',_N:'383',_C:'',_O:''},'biaoJiCode':{_C:'0104507',_E:'1704',_I:'1704'},'twoGuar':{_J:'402',_P:'40201',_D:'web_twoGuar'},'electTrend':{_C:_AY,_I:_L},'emergency':{_C:_AY,_D:'A10000000',_I:_L},'infoPublic':{_C:'2545454',_E:_w}} configuration={_K:{_W:_M,_Z:'',_a:'',_X:_x},_E:_b,_S:'32101',_I:_M,_AO:_M,'toPublish':_c,'siteId':'2012000000033700',_L:'',_N:'',_D:'',_C:{_y:_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',_S:'-1'},'userInformation':{_C:'01008183',_E:_b},'userInform':{_C:_r,_E:_b},'elesum':{_I:_M,_D:_z,_d:_G,_T:_G,_C:'0101143',_E:_A0},_A7:{_I:_M,_D:'WEBA1007200'},_Ac:{_E:_M,_S:'-1',_I:_s,_AO:_s,_C:_A8,_D:'WEBA40050000',_K:{_W:_M,_Z:'',_a:'',_X:_x}},'doorAuth':{_E:_b,_C:'f04'},'xinZ':{_O:'101',_Ad:'101','fJ_busiTypeCode':'102',_Ae:'03','fJ_custType':'02',_Af:_c,_P:'',_D:_AP,_y:_n,_E:_b,_A9:_G},'onedo':{_C:_AD,_E:_b,_D:_AP,'queryType':'03'},'xinHuTongDian':{_O:'110',_J:'211',_P:'21102',_D:'WEBA10071200',_I:_M,_E:_s,_C:_r},'company':{_O:'104',_D:_AP,_Af:'02',_A9:_G,_t:_G,_E:_b,_y:_n},'charge':{_I:_s,_D:'WEBA10071300',_AO:'0901',_O:'102',_Ae:_c,_Ad:'102'},'other':{_I:_s,_D:'WEBA10079700',_O:'129',_J:'999',_P:'21501',_C:_A1,_L:'',_N:''},'vatchange':{'submit':'0101003',_J:'320',_P:'',_O:'115',_D:'WEBA10074000',_t:_G},'bill':{_e:_G,_D:_z,_T:_G,_C:_A1},_V:{_I:_M,_D:_z,_T:_G,_e:_s,_C:_A1,_E:_A0},_m:{_I:_M,_e:'11',_D:_z,_d:_G,_T:_G,_C:_A1,_E:_A0},'mouthOut':{_I:_M,_e:'11',_D:_z,_d:_G,_T:_G,_C:_A1,_E:_A0},'meter':{_O:'114',_J:'304',_D:'WEBA10071000',_P:'',_C:_AD,_N:''},'complaint':{_J:'005','srvMode':_M,'anonymousFlag':'0','replyMode':_c,'retvisitFlag':_c},'report':{_J:'006'},'tradewinds':{_J:'019'},'somesay':{_J:'091'},'faultrepair':{_D:_Ag,_C:_r,_O:'111',_J:'001',_P:'21505'},'electronicInvoice':{_O:'105',_J:'0'},'rename':{_C:_AD,_D:'WEBA10076100',_J:'210',_O:'109',_t:_G,'gh_busiTypeCode':'211','gh_subusi':'21101',_N:'',_L:''},'pause':{_P:'',_C:_A8,_D:'WEBA10073600',_O:'107',_J:'203','jr_busi':'201',_N:'',_L:''},'capacityRecovery':{_C:_A8,_E:_b,_L:'',_N:'',_D:'WEBA10073700','busiTypeCode_stop':'204','busiTypeCode_less':'202',_J:'202',_P:'',_O:'108',_AQ:'5',_t:_G},'electricityPriceChange':{_C:_r,_J:'215',_P:'21502',_O:'113',_t:_G,_AQ:'15',_D:'WEBA10073900WEB',_L:'',_N:''},'electricityPriceStrategyChange':{_C:'01008183',_J:'215',_P:'21506',_O:'160',_D:'WEBV00000517WEB',_L:'',_N:''},'eemandValueAdjustment':{_C:_r,_L:'',_N:'',_O:'112',_D:'WEBA10073800',_J:'215',_P:'21504',_t:_G,_AQ:'5','getMonthServiceCode':_AD},'businessProgress':{_C:_r,_L:_c,_D:'WEB01'},'increase':{_E:_b,_N:'',_L:'',_Ah:_A8,_C:_n,_y:_n,_D:_AR,_A9:_G,_O:'106',_J:'111',_P:''},'fjincrea':{_O:'105',_J:'110',_P:'',_E:_b,_D:_AR,_N:'',_L:'',_Ah:_A8,_C:_n,_y:_n,_A9:_G},'persIncrea':{_O:'105',_J:'109',_y:_n,_P:'',_E:_b,_D:_AR,_A9:_G},'fgdChange':{_C:_r,_L:_c,_I:_s,_D:_Ag,_J:'215',_P:'21505',_O:'111',_t:_G},'createOrder':{_I:_M,_D:_z,_L:'BCP_000001','chargeMode':'02','conType':_c,'bizTypeId':'BT_ELEC'},'largePopulation':{_J:'383',_D:'WEBA10076800',_P:'',_L:'',_T:'',_d:'',_I:'0901',_O:'383',_C:'',_N:''},'biaoJiCode':{_C:'0104507',_E:'1704',_I:'1704'},'twoGuar':{_J:'402',_P:'40201',_D:'web_twoGuar'},'electTrend':{_C:_Ai,_I:_M},'emergency':{_C:_Ai,_D:'A10000000',_I:_M},'infoPublic':{_C:'2545454',_E:_A0}}
appKey='3def6c365d284881bf1a9b2b502ee68c' appKey='3def6c365d284881bf1a9b2b502ee68c'
appSecret='ab7357dae64944a197ace37398897f64' appSecret='ab7357dae64944a197ace37398897f64'
baseApi='https://www.95598.cn/api' baseApi='https://www.95598.cn/api'
@@ -120,13 +132,13 @@ get_door_number_api='/osg-open-uc0001/member/c9/f02'
get_door_balance_api='/osg-open-bc0001/member/c05/f01' get_door_balance_api='/osg-open-bc0001/member/c05/f01'
get_door_bill_api='/osg-open-bc0001/member/c01/f02' get_door_bill_api='/osg-open-bc0001/member/c01/f02'
get_door_ladder_api='/osg-open-bc0001/member/c04/f03' get_door_ladder_api='/osg-open-bc0001/member/c04/f03'
getJiaoFeiRecordApi=_AZ getJiaoFeiRecordApi=_Aj
get_door_daily_bill_api=_AZ get_door_daily_bill_api=_Aj
sessionIdControlApiList=[get_qr_code_api,get_qr_code_status_api,get_qr_code_token_api,send_code_api,code_login_api] sessionIdControlApiList=[get_qr_code_api,get_qr_code_status_api,get_qr_code_token_api,send_code_api,code_login_api]
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] 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]
authControlApiList=[get_door_number_api,get_door_balance_api,get_door_bill_api,get_door_ladder_api,getJiaoFeiRecordApi,get_door_daily_bill_api] authControlApiList=[get_door_number_api,get_door_balance_api,get_door_bill_api,get_door_ladder_api,getJiaoFeiRecordApi,get_door_daily_bill_api]
tControlApiList=[getCertificationApi,get_door_balance_api,get_door_bill_api,get_door_ladder_api,getJiaoFeiRecordApi,get_door_daily_bill_api] 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=_j) def json_dumps(data):return json.dumps(data,separators=(',',':'),ensure_ascii=_i)
def normal_round(num,ndigits=0): def normal_round(num,ndigits=0):
A=ndigits A=ndigits
if A==0:return int(num+.5) if A==0:return int(num+.5)
@@ -137,22 +149,21 @@ def catchFloat(data,key):
except:return 0 except:return 0
else:return 0 else:return 0
class StateGridDataClient: class StateGridDataClient:
hass=_G;session=_G;keyCode=_G;publicKey=_G;need_login=_j;phone=_G;codeKey=_G;serialNo=_G;qrCodeSerial=_G;userInfo=_G;accountInfo=_G;powerUserList=_G;doorAccountDict={};cookie=[];timestamp=int(time.time()*1000);accessToken=_G;refreshToken=_G;token=_G;expirationDate=_G;refresh_interval=12;is_debug=_j hass=_F;coordinator=_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=_G): def __init__(A,hass,config=_F):
B=config;A.hass=hass;C=aiohttp.TCPConnector(ssl=_j);D=aiohttp.CookieJar(quote_cookie=_y);A.session=aiohttp.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 _G: if B is not _F:
try:A.keyCode=B[_A5];A.publicKey=B[_AN];A.accessToken=B[_Aa];A.refreshToken=B[_Ab];A.token=B[_k];A.userInfo=B[_AA];A.powerUserList=B[_AO];A.doorAccountDict=B[_Ac];A.refresh_interval=B[_Ad];A.is_debug=B['is_debug'] try:A.keyCode=B[_AA];A.publicKey=B[_AS];A.accessToken=B[_Ak];A.refreshToken=B[_Al];A.token=B[_p];A.userInfo=B[_AE];A.powerUserList=B[_AT];A.doorAccountDict=B[_Am];A.refresh_interval=B[_An];A.is_debug=B['is_debug'];A.dataVersion=B[_Ao]
except Exception as E:LOGGER.error(E) except Exception as E:LOGGER.error(E)
async def save_data(A):B={};B[_A5]=A.keyCode;B[_AN]=A.publicKey;B[_Aa]=A.accessToken;B[_Ab]=A.refreshToken;B[_k]=A.token;B[_AA]=A.userInfo;B[_AO]=A.powerUserList;B[_Ac]=A.doorAccountDict;B[_Ad]=A.refresh_interval;B['is_debug']=A.is_debug;await async_save_to_store(A.hass,'state_grid.config',B) async def save_data(B):A={};A[_AA]=B.keyCode;A[_AS]=B.publicKey;A[_Ak]=B.accessToken;A[_Al]=B.refreshToken;A[_p]=B.token;A[_AE]=B.userInfo;A[_AT]=B.powerUserList;A[_Am]=B.doorAccountDict;A[_An]=B.refresh_interval;A['is_debug']=B.is_debug;A[_Ao]=VERSION;await async_save_to_store(B.hass,'state_grid.config',A)
def encrypt_post_data(A,data):B={_Ae:A.accessToken[len(A.accessToken)//2:]if A.accessToken else'','_t':A.token[len(A.token)//2:]if A.token else'','_data':data,_d:A.timestamp};return A.encrypt_wapper_data(B) def encrypt_post_data(A,data):B={_Ap: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):B=a(json_dumps(data),A.keyCode);return{_A:B+c(B+str(A.timestamp)),_AB:d(A.keyCode,A.publicKey),_d:str(A.timestamp)} def encrypt_wapper_data(A,data):B=a(json_dumps(data),A.keyCode);return{_A:B+c(B+str(A.timestamp)),_AF:d(A.keyCode,A.publicKey),_j:str(A.timestamp)}
def handle_request_result_message(E,api,result): def handle_request_result_message(E,api,result):
D='message';C='resultMessage';A=result;B=_G D='message';C='resultMessage';A=result;LOGGER.error(api+'-'+json_dumps(A));B=_F
if _A in A and _Q in A[_A]and C in A[_A][_Q]:B=A[_A][_Q][C] if _A in A and _Q in A[_A]and C in A[_A][_Q]:B=A[_A][_Q][C]
elif _Q in A and C in A[_Q]:B=A[_Q][C] elif _Q in A and C in A[_Q]:B=A[_Q][C]
elif D in A:B=A[D] elif D in A:B=A[D]
else:B=json_dumps(A) else:B=json_dumps(A)
if E.is_debug:LOGGER.error(api+': '+B);LOGGER.error(json_dumps(A))
return B return B
async def __fetch_safe(C,api,data): async def __fetch_safe(C,api,data):
B=await C.__fetch(api,data) B=await C.__fetch(api,data)
@@ -160,24 +171,24 @@ class StateGridDataClient:
A=B[_H] 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: 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() await C.__refresh_token()
if C.need_login is _y:return B if C.need_login is _o:return B
else:return await C.__fetch(api,data) else:return await C.__fetch(api,data)
else:return B else:return B
async def __fetch(B,api,data,header=_G): 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 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 _G:B.keyCode=e(32,16,2) 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',_d:str(D),'wsgwType':'web','appKey':appKey};A=data 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)),_AB:d(F,'042BC7AD510BF9793B7744C8854C56A8C95DD1027EE619247A332EC6ED5B279F435A23D62441FE861F4B0C963347ECD5792F380B64CA084BE8BE41151F8B8D19C8'),I:appKey,_d:str(D)} if E==get_request_key_api:A={I:appKey,K:appSecret};H=a(json_dumps(A),F);A={_A:H+c(H+str(D)),_AF:d(F,'042BC7AD510BF9793B7744C8854C56A8C95DD1027EE619247A332EC6ED5B279F435A23D62441FE861F4B0C963347ECD5792F380B64CA084BE8BE41151F8B8D19C8'),I:appKey,_j:str(D)}
elif E==get_qr_code_api:A={_Ae:'','_t':'','_data':A,_d:D} elif E==get_qr_code_api:A={_Ap:'','_t':'','_data':A,_j:D}
elif E==get_request_authorize_api: elif E==get_request_authorize_api:
A={I:appKey,'response_type':_H,_Af:'/test',_d:D,'rsi':B.token};A=urllib.parse.urlencode(A);G[M]='application/x-www-form-urlencoded; charset=UTF-8';G[_A5]=F A={I:appKey,'response_type':_H,_Aq:'/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 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,_d:D,_H:A[_H]};H=a(json_dumps(A),F);A={_A:H+c(H+str(D)),_AB:d(F,B.publicKey),_d:str(D)} 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)),_AF:d(F,B.publicKey),_j:str(D)}
elif E==refresh_web_token_api:A={O:_AC,P:c(appKey+str(D)),K:appSecret,Q:S,R:F,I:appKey,_d:D,_AC:B.refreshToken};H=a(json_dumps(A),F);A={_A:H+c(H+str(D)),_AB:d(F,B.publicKey),_d:str(D)};E=get_web_token_api elif E==refresh_web_token_api:A={O:_AG,P:c(appKey+str(D)),K:appSecret,Q:S,R:F,I:appKey,_j:D,_AG:B.refreshToken};H=a(json_dumps(A),F);A={_A:H+c(H+str(D)),_AF:d(F,B.publicKey),_j:str(D)};E=get_web_token_api
else:A=B.encrypt_post_data(A) else:A=B.encrypt_post_data(A)
if L is not _G:G.update(L) if L is not _F:G.update(L)
if E in sessionIdControlApiList:G['sessionId']='web'+str(D) if E in sessionIdControlApiList:G['sessionId']='web'+str(D)
if E in keyCodeControlApiList:G[_A5]=F if E in keyCodeControlApiList:G[_AA]=F
if E in authControlApiList:G['Authorization']='Bearer '+B.accessToken[:len(B.accessToken)//2] 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] 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: async with B.session.post(baseApi+E,json=A,headers=G)as J:
@@ -187,74 +198,101 @@ class StateGridDataClient:
if T in C:C=b(C[T],F);C=json.loads(C) if T in C:C=b(C[T],F);C=json.loads(C)
return C return C
async def __get_request_key(A): async def __get_request_key(A):
A.keyCode=_G;B=await A.__fetch(get_request_key_api,{});C=A.handle_request_result_message('get_request_key_api',B) A.keyCode=_F;B=await A.__fetch(get_request_key_api,{});C=A.handle_request_result_message('get_request_key_api',B)
if B[_H]==_F:A.keyCode=B[_A][_A5];A.publicKey=B[_A][_AN];return{_B:0} if B[_H]==_G:A.keyCode=B[_A][_AA];A.publicKey=B[_A][_AS];return{_B:0}
return{_B:1,_b:C} return{_B:1,_f:C}
async def __get_qr_code(B): async def __get_qr_code(B):
C={_K:{_X:'',_V:_t,_U:_L,_Y:''},_z:{'optType':_a,_O:e(28,10,1)}};A=await B.__fetch(get_qr_code_api,C);D=B.handle_request_result_message('get_qr_code_api',A) C={_K:{_Z:'',_X:_x,_W:_M,_a:''},_A2:{'optType':_c,_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 A[_H]==1: if A[_H]==1:
if A[_A]and A[_A][_Q]and A[_A][_Q][_A0]==_AD:B.qrCodeSerial=A[_A][_g][_Ag];E=A[_A][_g]['qrCode'];return{_B:0,_A:E} if A[_A]and A[_A][_Q]and A[_A][_Q][_A3]==_AH:B.qrCodeSerial=A[_A][_k][_Ar];E=A[_A][_k]['qrCode'];return{_B:0,_A:E}
return{_B:1,_b:D} return{_B:1,_f:D}
async def __get_qr_code_status(B): async def __get_qr_code_status(B):
C={_g:{_Ag: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) C={_k:{_Ar:B.qrCodeSerial}};D={_p:'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 _H in A and A[_H]==1: if _H in A and A[_H]==1:
if _A in A and A[_A]!='null':B.token=A[_A];return{_B:0} if _A in A and A[_A]!='null':B.token=A[_A];return{_B:0}
else:return{_B:1,_b:'未使用网上国网 App 扫码或确认登录'} else:return{_B:1,_f:'未使用网上国网 App 扫码或确认登录'}
return{_B:1,_b:E} return{_B:1,_f:E}
async def __get_qr_code_token(B): async def __get_qr_code_token(B):
C={_K:{_V:_t,_U:_L,'isEncrypt':_y},_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) C={_K:{_X:_x,_W:_M,'isEncrypt':_o},_p: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 _Q in A and _A0 in A[_Q]and A[_Q][_A0]==_AD:B.userInfo=A[_g][_AA];return{_B:0} if _Q in A and _A3 in A[_Q]and A[_Q][_A3]==_AH:B.userInfo=A[_k][_AE];return{_B:0}
return{_B:1,_b:D} return{_B:1,_f:D}
async def __send_code(B,phone): async def __send_code(B,phone):
C=phone;B.phone=C;D={_K:{_X:'',_V:_t,_U:_L,_Y:''},_z:{'sendType':'0',_A2:C,_Ah:'login','accountType':''},'Channels':'web'};A=await B.__fetch(send_code_api,D);E=B.handle_request_result_message('send_code_api',A) C=phone;B.phone=C;D={_K:{_Z:'',_X:_x,_W:_M,_a:''},_A2:{'sendType':'0',_A7:C,_As:'login','accountType':''},'Channels':'web'};A=await B.__fetch(send_code_api,D);E=B.handle_request_result_message('send_code_api',A)
if A[_H]==1: if A[_H]==1:
if A[_A]and A[_A][_Q]and A[_A][_Q][_A0]==_AD:B.codeKey=A[_A][_g]['codeKey'];return{_B:0} if A[_A]and A[_A][_Q]and A[_A][_Q][_A3]==_AH:B.codeKey=A[_A][_k]['codeKey'];return{_B:0}
return{_B:1,_b:E} return{_B:1,_f:E}
async def __verfiy_code(A,code): async def __verfiy_code(A,code):
C={_K:{_X:'',_V:_t,_U:_L,_Y:''},_z:{_A2:A.phone,_Ah:'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) C={_K:{_Z:'',_X:_x,_W:_M,_a:''},_A2:{_A7:A.phone,_As:'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 _Q in B and _A0 in B[_Q]and B[_Q][_A0]==_AD:A.token=B[_g][_k];A.userInfo=B[_g][_AA][0];return{_B:0} if _Q in B and _A3 in B[_Q]and B[_Q][_A3]==_AH:A.token=B[_k][_p];A.userInfo=B[_k][_AE][0];return{_B:0}
return{_B:1,_b:D} return{_B:1,_f:D}
async def __get_request_authorize(B): async def __get_request_authorize(B):
A=await B.__fetch(get_request_authorize_api,{});E=B.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 _H in A and A[_H]==_F:C=A[_A][_Af];D=C.rfind('code=');B.authorizeCode=C[D+5:D+5+32];return{_B:0} if _H in A and A[_H]==_G:C=A[_A][_Aq];D=C.rfind('code=');B.authorizeCode=C[D+5:D+5+32];return{_B:0}
return{_B:1,_b:E} return{_B:1,_f:E}
async def __get_web_token(A): async def __get_web_token(A):
C={_H:A.authorizeCode};B=await A.__fetch(get_web_token_api,C);D=A.handle_request_result_message('get_web_token_api',B) 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 _H in B and B[_H]==_F:A.accessToken=B[_A][_Ai];A.refreshToken=B[_A][_AC];return{_B:0} if _H in B and B[_H]==_G:A.accessToken=B[_A][_At];A.refreshToken=B[_A][_AG];return{_B:0}
return{_B:1,_b:D} return{_B:1,_f:D}
async def __refresh_web_token(B): async def __refresh_web_token(B):
A=await B.__fetch(refresh_web_token_api,{});C=B.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 _H in A and A[_H]==_F:B.accessToken=A[_A][_Ai];B.refreshToken=A[_A][_AC];return{_B:0} if _H in A and A[_H]==_G:B.accessToken=A[_A][_At];B.refreshToken=A[_A][_AG];return{_B:0}
return{_B:1,_b:C} return{_B:1,_f:C}
async def __get_door_number(C): async def __get_door_number(A):
A=configuration[_AS];D={_C:A[_C],_E:A[_E],_R:A[_R],_K:{_U:A[_K][_U],_X:A[_K][_X],_Y:A[_K][_Y],_V:A[_K][_V]},_z:{_S:C.userInfo[_S]},_k:C.token};B=await C.__fetch_safe(get_door_number_api,D);E=C.handle_request_result_message('get_door_number_api',B) B=configuration[_Ac];G={_C:B[_C],_E:B[_E],_S:B[_S],_K:{_W:B[_K][_W],_Z:B[_K][_Z],_a:B[_K][_a],_X:B[_K][_X]},_A2:{_R:A.userInfo[_R]},_p:A.token};C=await A.__fetch_safe(get_door_number_api,G);H=A.handle_request_result_message('get_door_number_api',C)
if _H in B and B[_H]==1 and _A in B and _g in B[_A]:C.powerUserList=B[_A][_g][_AO];return{_B:0} if _H in C and C[_H]==1 and _A in C and _k in C[_A]:
return{_B:1,_b:E} E={}
if A.powerUserList is not _F:E={A[_g]:A for A in A.powerUserList}
F=[]
for D in C[_A][_k][_AT]:
if D[_g]in E:F.append(E[D[_g]])
elif _AU in D and D[_AU]!='05':F.append(D)
A.powerUserList=F;return{_B:0}
return{_B:1,_f:H}
async def __get_door_balance(B,door_account): async def __get_door_balance(B,door_account):
A=door_account;E={_A:{_M:'',_O:'',_I:configuration[_A2][_I],_D:configuration[_A2][_D],_A6:B.userInfo[_S],_A7:B.userInfo.get(_AE,B.userInfo.get('nickname',_G)),_T:_F,_c:_F,_AP:B.userInfo[_S],_A8:[{'consNoSrc':A[_r],_AF:A.get(_W,A.get(_AG,_G)),'sceneType':A.get('consSortCode',A.get('elecTypeCode',_G)),_q:A[_q],_e:A[_e]}]},_C:'0101143',_E:configuration[_E],_R:A.get(_W,A.get(_AG,_G))};C=await B.__fetch_safe(get_door_balance_api,E);B.handle_request_result_message('get_door_balance_api',C) A=door_account;E={_A:{_L:'',_N:'',_I:configuration[_A7][_I],_D:configuration[_A7][_D],_A4:B.userInfo[_R],_A5:B.userInfo.get(_AB,B.userInfo.get('nickname',_F)),_T:_G,_d:_G,_AI:B.userInfo[_R],_u:[{'consNoSrc':A[_g],_AJ:A.get(_U,A.get(_AK,_F)),'sceneType':A.get('consSortCode',A.get(_AU,_F)),_q:A[_q],_Y:A[_Y]}]},_C:'0101143',_E:configuration[_E],_S:A.get(_U,A.get(_AK,_F))};C=await B.__fetch_safe(get_door_balance_api,E);B.handle_request_result_message('get_door_balance_api',C)
if _H in C and C[_H]==1 and _A in C and _A8 in C[_A]: if _H in C and C[_H]==1 and _A in C and _u in C[_A]:
D=C[_A][_A8] D=C[_A][_u]
if len(D)!=0:A[_A1]=D[0] if len(D)!=0:A[_v]=D[0]
async def __get_door_bill(C,door_account,year): async def __get_door_bill(C,door_account,monthDate):
E='dataInfo';D='mothEleList';B=door_account;F={_A:{_A6:C.userInfo[_S],_I:configuration[_I],_f:'11',_AQ:B[_Al],_D:'ALIPAY_01',_e:B[_e],_AF:B[_W],_c:_F,_T:_F,_O:'',_M:'',_A7:'',_Aj:B[_W],_AP:C.userInfo[_S],_q:B[_q],_Ak:year},_C:_x,_E:_w,_R:B[_W]};A=await C.__fetch_safe(get_door_bill_api,F);C.handle_request_result_message('get_door_bill_api',A) I='dataInfo';G='mothEleList';E=monthDate;A=door_account;J={_A:{_A4:C.userInfo[_R],_I:configuration[_I],_e:'11',_AL:A[_AW],_D:'ALIPAY_01',_Y:A[_Y],_AJ:A[_U],_d:_G,_T:_G,_N:'',_L:'',_A5:'',_AV:A[_U],_AI:C.userInfo[_R],_q:A[_q],_Au:E.year},_C:_A1,_E:_A0,_S:A[_U]};B=await C.__fetch_safe(get_door_bill_api,J);C.handle_request_result_message('get_door_bill_api',B)
if _H in A and A[_H]==1 and _A in A: if _H in B and B[_H]==1 and _A in B:
if E in A[_A]:B[_AH]=A[_A][E] if I in B[_A]:A[_AM]=B[_A][I]
if D in A[_A]: if G in B[_A]:
B[_AI]=A[_A][D] if _AC not in A or A[_AC]!=E.year:A[_l]=B[_A][G];A[_AC]=E.year
if len(A[_A][D])!=0:B[_s]=A[_A][D][-1] else:
async def __get_door_ladder(B,door_account,month): F={A.month:A for A in A[_l]};H=B[_A][G]
F='ladder_flag';E=month;A=door_account;G=A[_r];H={_A:{_I:configuration[_m][_I],_D:configuration[_m][_D],_T:configuration[_m][_T],_f:configuration[_m][_f],_q:A[_r],_c:A[_W],_e:A[_e],'queryDate':E,_Aj:A[_W],_AQ:A[_Al],_AP:B.userInfo[_S],_O:'',_M:'',_A7:B.userInfo[_AE],_A6:B.userInfo[_S]},_C:configuration[_m][_C],_E:configuration[_m][_E],_R:A[_W]};C=await B.__fetch(get_door_ladder_api,H);I=B.handle_request_result_message('get_door_ladder_api',C) for D in H:
if _H in C and C[_H]==1 and _A in C and _A8 in C[_A]: if D.month in F and _h in F[D.month]:D[_h]=F[D.month][_h]
D=C[_A][_A8] A[_l]=H
if len(D)!=0: if len(A[_l])>0:A[_w]=A[_l][-1]
D=D[0];D[_AR]=E async def __get_door_ladder(C,door_account,monthBill):
if D['electricParticulars']['levelFlag']=='2':A[F]=1 E=monthBill;A=door_account;I=A[_g];F=datetime.datetime.strptime(E[_AN],'%Y%m');G=f"{F.year}-{F.month:02d}";H={_A:{_I:configuration[_V][_I],_D:configuration[_V][_D],_T:configuration[_V][_T],_e:configuration[_V][_e],_q:A[_g],_d:A[_U],_Y:A[_Y],_Av:G,_AV:A[_U],_AL:A[_AW],_AI:C.userInfo[_R],_N:'',_L:'',_A5:C.userInfo[_AB],_A4:C.userInfo[_R]},_C:configuration[_V][_C],_E:configuration[_V][_E],_S:A[_U]};B=await C.__fetch(get_door_ladder_api,H);J=C.handle_request_result_message(_Aw,B)
else:A[F]=0 if _H in B and B[_H]==1 and _A in B and _u in B[_A]:
B.doorAccountDict[G]['ladder']=D D=B[_A][_u]
if len(D)!=0:D=D[0];E['ladder']=D
async def __get_door_mouth_bill(I,door_account,monthBill):
S=monthBill;O='quantity';N='priceName';K='amtGroupList';H='readList';E=door_account;C='amtList';B='pointList';T=datetime.datetime.strptime(S[_AN],'%Y%m');V=f"{T.year}-{T.month:02d}";W={_A:{_I:configuration[_V][_I],_D:configuration[_V][_D],_T:configuration[_V][_T],_e:configuration[_V][_e],_q:E[_g],_d:E[_U],_Y:E[_Y],_Av:V,_AV:E[_U],_AL:E[_AW],_AI:I.userInfo[_R],_N:'',_L:'',_A5:I.userInfo[_AB],_A4:I.userInfo[_R]},_C:configuration[_V][_C],_E:configuration[_V][_E],_S:E[_U]};F=await I.__fetch(get_door_ladder_api,W);X=I.handle_request_result_message(_Aw,F)
if _H in F and F[_H]==1 and _A in F and _u in F[_A]:
A=F[_A][_u][0];U=0;P=0;Q=0;L=0;R=0;M=[]
if H in A and len(A[H])>0:M=A[H]
elif B in A and len(A[B])>0 and H in A[B][0]and len(A[B][0][H])>0:M=A[B][0][H]
if len(M)>0:U=catchFloat(M[0],'activeCount')
J=[]
if C in A and len(A[C])>0:J=A[C]
elif B in A and len(A[B])>0 and C in A[B][0]and len(A[B][0][C])>0:J=A[B][0][C]
elif B in A and len(A[B])>0 and K in A[B][0]and len(A[B][0][K])>0 and C in A[B][0][K][0]and len(A[B][0][K][0][C])>0:J=A[B][0][K][0][C]
if len(J)>0:
for D in J:
if D[N]=='':P=catchFloat(D,O)
elif D[N]=='':Q=catchFloat(D,O)
elif D[N]=='':L=catchFloat(D,O)
elif D[N]=='':R=catchFloat(D,O)
if L==0:L=P+Q+R
G={};G[_AX]=normal_round(U,2);G[_AY]=normal_round(P,2);G[_AZ]=normal_round(Q,2);G[_Aa]=normal_round(L,2);G[_Ab]=normal_round(R,2);S[_h]=G
async def __get_door_daily_bill(B,door_account,year,start_date,end_date): async def __get_door_daily_bill(B,door_account,year,start_date,end_date):
D='sevenEleList';A=door_account;E={'params1':{_C:configuration[_C],_E:configuration[_E],_R:configuration[_R],_K:{_U:configuration[_K][_U],_X:configuration[_K][_X],_Y:configuration[_K][_Y],_V:configuration[_K][_V]},_z:{_S:B.userInfo[_S]},_k:B.token},'params3':{_A:{_A6:B.userInfo[_S],_q:A[_r],_AQ:_a,'endTime':end_date,_e:A[_e],_Ak:year,_AF:A.get(_W,A.get(_AG,_G)),_O:'',_M:'','startTime':start_date,_A7:B.userInfo[_AE],_D:configuration[_h][_D],_I:configuration[_h][_I],_f:configuration[_h][_f],_c:configuration[_h][_c],_T:configuration[_h][_T]},_C:configuration[_h][_C],_E:configuration[_h][_E],_R:A.get(_W,A.get(_AG,_G))},'params4':'010103'};C=await B.__fetch_safe(get_door_daily_bill_api,E);F=B.handle_request_result_message('get_door_daily_bill_api',C) D='sevenEleList';A=door_account;E={'params1':{_C:configuration[_C],_E:configuration[_E],_S:configuration[_S],_K:{_W:configuration[_K][_W],_Z:configuration[_K][_Z],_a:configuration[_K][_a],_X:configuration[_K][_X]},_A2:{_R:B.userInfo[_R]},_p:B.token},'params3':{_A:{_A4:B.userInfo[_R],_q:A[_g],_AL:_c,'endTime':end_date,_Y:A[_Y],_Au:year,_AJ:A.get(_U,A.get(_AK,_F)),_N:'',_L:'','startTime':start_date,_A5:B.userInfo[_AB],_D:configuration[_m][_D],_I:configuration[_m][_I],_e:configuration[_m][_e],_d:configuration[_m][_d],_T:configuration[_m][_T]},_C:configuration[_m][_C],_E:configuration[_m][_E],_S:A.get(_U,A.get(_AK,_F))},'params4':'010103'};C=await B.__fetch_safe(get_door_daily_bill_api,E);F=B.handle_request_result_message('get_door_daily_bill_api',C)
if _H in C and C[_H]==1 and _A in C and D in C[_A]:A[_l]=C[_A][D] if _H in C and C[_H]==1 and _A in C and D in C[_A]:A[_A6]=C[_A][D]
async def __get_door_pay_record(A,door_account):B=door_account;D=B[_r];C={'params1':{_C:configuration[_C],_E:configuration[_E],_R:configuration[_R],_K:{_U:configuration[_K][_U],_X:configuration[_K][_X],_Y:configuration[_K][_Y],_V:configuration[_K][_V]},_z:{_S:A.userInfo[_S]},_k:A.token},'params3':{_A:{_A6:A.userInfo[_S],'bgnPayDate':'2023-04-24',_I:configuration[_I],_q:B[_r],'endPayDate':'2024-04-24',_D:'webALIPAY_01','number':100,_e:B[_e],'page':_F,_AF:B[_W],_c:_F,_T:_F,_O:'',_M:'',_A7:A.userInfo[_AE]},_C:'0101051',_E:_a,_R:B[_W]},'params4':'010104'};E=await A.__fetch(getJiaoFeiRecordApi,C) async def __get_door_pay_record(A,door_account):B=door_account;D=B[_g];C={'params1':{_C:configuration[_C],_E:configuration[_E],_S:configuration[_S],_K:{_W:configuration[_K][_W],_Z:configuration[_K][_Z],_a:configuration[_K][_a],_X:configuration[_K][_X]},_A2:{_R:A.userInfo[_R]},_p:A.token},'params3':{_A:{_A4:A.userInfo[_R],'bgnPayDate':'2023-04-24',_I:configuration[_I],_q:B[_g],'endPayDate':'2024-04-24',_D:'webALIPAY_01','number':100,_Y:B[_Y],'page':_G,_AJ:B[_U],_d:_G,_T:_G,_N:'',_L:'',_A5:A.userInfo[_AB]},_C:'0101051',_E:_c,_S:B[_U]},'params4':'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 _B in A and A[_B]!=0:return A if _B in A and A[_B]!=0:return A
@@ -282,69 +320,77 @@ class StateGridDataClient:
if _B in A and A[_B]!=0:return A if _B in A and A[_B]!=0:return A
A=await B.__get_door_number() A=await B.__get_door_number()
if _B in A and A[_B]!=0:return A if _B in A and A[_B]!=0:return A
B.need_login=_j;await B.save_data();return{_B:0,_A:B.powerUserList} B.need_login=_i;await B.save_data();return{_B:0,_A:B.powerUserList}
async def __refresh_token(A): async def __refresh_token(A):
B=await A.__get_request_key() B=await A.__get_request_key()
if _B in B and B[_B]!=0:return if _B in B and B[_B]!=0:return
B=await A.__refresh_web_token() B=await A.__refresh_web_token()
if _B in B and B[_B]==0:A.need_login=_j;await A.save_data() if _B in B and B[_B]==0:A.need_login=_i;A.retry_times=0;await A.save_data()
else:A.need_login=_y;LOGGER.error('国家电网刷新 Token 失败') elif A.retry_times>=3:A.need_login=_o
async def refresh_data(C,setup=_j): else:A.retry_times=A.retry_times+1
j='last_month_ele_cost';i='monthEleNum';h='year_ele_cost';g='thisTPq';f='thisNPq';e='thisVPq';d='thisPPq';U=setup;T='ladder_level_num';S='ladder_level';R='last_month_ele_num';Q='year_ele_num';L='%Y%m%d';K='day';I='dayElePq';H='balance' async def refresh_data(B,setup=_i,force_refresh=_i):
if U is _y:await C.__get_door_number() t='last_month_ele_cost';s='year_ele_cost';r='thisTPq';q='thisNPq';p='thisVPq';o='thisPPq';n='%Y%m%d';m='day';l='refresh_time';f=setup;e='last_month_ele_num';d='dayElePq';U='year_ele_num';G='balance'
if C.need_login is _y:LOGGER.error('国家电网需要重新登录!');return if f is _o:
k=U or int(time.time()*1000)-C.timestamp>C.refresh_interval*3600*1000 if B.dataVersion!=VERSION:B.powerUserList=_F
if k is _j:return g=await B.__get_door_number()
M=datetime.datetime.now();J=M-datetime.timedelta(days=1);l=f"{J.year}-{J.month:02d}-{J.day:02d}";N=J-datetime.timedelta(days=40);m=f"{N.year}-{N.month:02d}-{N.day:02d}" if _B in g and g[_B]!=0:B.need_login=_o
for A in C.powerUserList: if B.need_login is _o:
n=A[_r];C.doorAccountDict[n]=A;await C.__get_door_balance(A) if B.powerUserList is not _F:
if _A1 in A: for A in B.get_door_account_list():A[l]='Token刷新失败,请重新登录'
o=catchFloat(A[_A1],'estiAmt');V=catchFloat(A[_A1],'prepayBal');p=catchFloat(A[_A1],'sumMoney') LOGGER.error('国家电网 - Token刷新失败,请重新登录!');return
if V==0:A[H]=p u=f or force_refresh or int(time.time()*1000)-B.timestamp>B.refresh_interval*3600*1000
else:A[H]=V-o if u is _i:return
W=catchFloat(A[_A1],'historyOwe') V=datetime.datetime.now();H=V-datetime.timedelta(days=1);v=f"{H.year}-{H.month:02d}-{H.day:02d}";W=H-datetime.timedelta(days=40);w=f"{W.year}-{W.month:02d}-{W.day:02d}"
if W>0:A[H]=-W for A in B.powerUserList:
x=A[_g];B.doorAccountDict[x]=A;await B.__get_door_balance(A)
if B.retry_times!=0:return
if _v in A:
y=catchFloat(A[_v],'accountBalance');z=catchFloat(A[_v],'estiAmt');X=catchFloat(A[_v],'prepayBal');Y=catchFloat(A[_v],'sumMoney')
if y!=0:A[G]=Y
elif X==0 or X==Y:A[G]=Y
else:A[G]=X-z
h=catchFloat(A[_v],'historyOwe')
if h>0:A[G]=-h
else:LOGGER.error('国家电网账户余额获取失败!') else:LOGGER.error('国家电网账户余额获取失败!')
if H not in A:A[H]=0 if G not in A:A[G]=0
await C.__get_door_daily_bill(A,M.year,m,l) await B.__get_door_daily_bill(A,V.year,w,v)
if _l not in A:LOGGER.error('国家电网无法获取日用电数据!');return if _A6 not in A:LOGGER.error('国家电网无法获取日用电数据!');continue
O=0 Z=0;L=_i
for X in range(10): for i in range(10):
D=A[_l][X] D=A[_A6][i]
try:float(D[I]);break try:float(D[d]);L=_o;break
except:O=O+1 except:Z=Z+1
for X in range(O):A[_l].pop(0) j=0;a=0;b=0;M=0;c=0
D=A[_l][0];E=datetime.datetime.strptime(D[K],L);A['daily_ele_num']=catchFloat(D,I);A['daily_p_ele_num']=catchFloat(D,d);A['daily_v_ele_num']=catchFloat(D,e);A['daily_n_ele_num']=catchFloat(D,f);A['daily_t_ele_num']=catchFloat(D,g);Y=0;Z=0;a=0;b=0;c=0 if L:
for B in A[_l]: for i in range(Z):A[_A6].pop(0)
G=datetime.datetime.strptime(B[K],L) D=A[_A6][0];E=datetime.datetime.strptime(D[m],n);A['daily_lasted_date']=f"{E.year}-{E.month:02d}-{E.day:02d}";j=catchFloat(D,d);a=catchFloat(D,o);b=catchFloat(D,p);M=catchFloat(D,q);c=catchFloat(D,r)
if G.month!=E.month:break if M==0:M=a+b+c
Y+=catchFloat(B,I);Z+=catchFloat(B,d);a+=catchFloat(B,e);b+=catchFloat(B,f);c+=catchFloat(B,g) A['daily_ele_num']=normal_round(j,2);A['daily_p_ele_num']=normal_round(a,2);A['daily_v_ele_num']=normal_round(b,2);A['daily_n_ele_num']=normal_round(M,2);A['daily_t_ele_num']=normal_round(c,2);N=0;I=0;J=0;F=0;K=0
A['month_ele_num']=normal_round(Y,2);A['month_p_ele_num']=normal_round(Z,2);A['month_v_ele_num']=normal_round(a,2);A['month_n_ele_num']=normal_round(b,2);A['month_t_ele_num']=normal_round(c,2);P=E-datetime.timedelta(days=E.day);q=f"{P.year}-{P.month:02d}" if L:
if _s not in A or A[_s][_AR]!=q:await C.__get_door_bill(A,P.year) for C in A[_A6]:
if _s not in A:LOGGER.error('国家电网无法获取年度用电数据!');return A0=datetime.datetime.strptime(C[m],n)
if _AH in A:A[Q]=catchFloat(A[_AH],'totalEleNum');A[h]=catchFloat(A[_AH],'totalEleCost') if A0.month!=E.month:break
if Q not in A:A[Q]=0;A[h]=0 N+=catchFloat(C,d);I+=catchFloat(C,o);J+=catchFloat(C,p);F+=catchFloat(C,q);K+=catchFloat(C,r)
if _AI in A:A[R]=catchFloat(A[_s],i);A[j]=catchFloat(A[_s],'monthEleCost') if F==0:F=I+J+K
if R not in A:A[R]=0;A[j]=0 A[_AX]=normal_round(N,2);A[_AY]=normal_round(I,2);A[_AZ]=normal_round(J,2);A[_Aa]=normal_round(F,2);A[_Ab]=normal_round(K,2)
r=datetime.datetime.strptime(A[_s][_AR],'%Y%m') if L:
if r.month==12: O=E-datetime.timedelta(days=E.day);A1=f"{O.year}{O.month:02d}"
F=0 if _AC not in A or A[_AC]!=O.year or _w not in A or A[_w][_AN]!=A1:await B.__get_door_bill(A,O)
for B in A[_l]: if _l in A:
G=datetime.datetime.strptime(B[K],L) for C in A[_l]:
if G.month!=12:break if _h not in C:await B.__get_door_mouth_bill(A,C)
F+=catchFloat(B,I) if _AM in A:A[U]=catchFloat(A[_AM],'totalEleNum');A[s]=catchFloat(A[_AM],'totalEleCost')
if U not in A:A[U]=0;A[s]=0
if _w in A:A[e]=catchFloat(A[_w],'monthEleNum');A[t]=catchFloat(A[_w],'monthEleCost');k=datetime.datetime.strptime(A[_w][_AN],'%Y%m')
if e not in A:A[e]=0;A[t]=0;k=H
P=0;Q=0;R=0;S=0;T=0
if k.month==12:P=N;Q=I;R=J;S=F;T=K
else: else:
F=0 if _l in A:
for B in A[_AI]:F+=catchFloat(B,i) for C in A[_l]:
s=len(A[_AI]) if _h in C:P+=C[_h][_AX];Q+=C[_h][_AY];R+=C[_h][_AZ];S+=C[_h][_Aa];T+=C[_h][_Ab]
for B in A[_l]: P+=N;Q+=I;R+=J;S+=F;T+=K
G=datetime.datetime.strptime(B[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[l]=datetime.datetime.strftime(V,'%Y-%m-%d %H:%M:%S')
if G.month<=s:break await B.save_data()
F+=catchFloat(B,I) def get_door_account_list(A):return list(A.doorAccountDict.values())
if F<=2760:A[S]='第一阶梯';A[T]=1
elif F<=4800:A[S]='第二阶梯';A[T]=2
else:A[S]='第三阶梯';A[T]=3
A['daily_lasted_date']=f"{E.year}-{E.month:02d}-{E.day:02d}";A['refresh_time']=datetime.datetime.strftime(M,'%Y-%m-%d %H:%M:%S')
await C.save_data()
async 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
+1 -1
View File
@@ -5,5 +5,5 @@
"config_flow": true, "config_flow": true,
"documentation": "https://hassbox.cn/", "documentation": "https://hassbox.cn/",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"version": "0.0.8" "version": "0.1.9"
} }
+85 -36
View File
@@ -16,7 +16,6 @@ from .const import DOMAIN, VERSION
from .data_client import StateGridDataClient from .data_client import StateGridDataClient
from .coordinator import StateGridCoordinator from .coordinator import StateGridCoordinator
UNIT_DU = ""
UNIT_YUAN = "" UNIT_YUAN = ""
ENTITY_ID_SENSOR_FORMAT = SENSOR_DOMAIN + ".state_grid_" ENTITY_ID_SENSOR_FORMAT = SENSOR_DOMAIN + ".state_grid_"
@@ -25,96 +24,139 @@ SENSOR_TYPES = [
{ {
"key":"balance", "key":"balance",
"name": "账户余额", "name": "账户余额",
"unit_of_measurement": UNIT_YUAN, "native_unit_of_measurement": UNIT_YUAN,
"native_unit_of_measurement": UNIT_YUAN "device_class": SensorDeviceClass.MONETARY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "year_ele_num", "key": "year_ele_num",
"name": "年度累计用电", "name": "年度累计用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
},
{
"key": "year_p_ele_num",
"name": "年度累计峰用电",
"native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
},
{
"key": "year_v_ele_num",
"name": "年度累计谷用电",
"native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
},
{
"key": "year_n_ele_num",
"name": "年度累计平用电",
"native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
},
{
"key": "year_t_ele_num",
"name": "年度累计尖用电",
"native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "year_ele_cost", "key": "year_ele_cost",
"name": "年度累计电费", "name": "年度累计电费",
"unit_of_measurement": UNIT_YUAN, "native_unit_of_measurement": UNIT_YUAN,
"native_unit_of_measurement": UNIT_YUAN "device_class": SensorDeviceClass.MONETARY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "last_month_ele_num", "key": "last_month_ele_num",
"name": "上个月用电", "name": "上个月用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "last_month_ele_cost", "key": "last_month_ele_cost",
"name": "上个月电费", "name": "上个月电费",
"unit_of_measurement": UNIT_YUAN, "native_unit_of_measurement": UNIT_YUAN,
"native_unit_of_measurement": UNIT_YUAN "device_class": SensorDeviceClass.MONETARY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "month_ele_num", "key": "month_ele_num",
"name": "当月累计用电", "name": "当月累计用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "month_p_ele_num", "key": "month_p_ele_num",
"name": "当月累计峰用电", "name": "当月累计峰用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "month_v_ele_num", "key": "month_v_ele_num",
"name": "当月累计谷用电", "name": "当月累计谷用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "month_n_ele_num", "key": "month_n_ele_num",
"name": "当月累计平用电", "name": "当月累计平用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "month_t_ele_num", "key": "month_t_ele_num",
"name": "当月累计尖用电", "name": "当月累计尖用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "daily_ele_num", "key": "daily_ele_num",
"name": "日总用电", "name": "日总用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "daily_p_ele_num", "key": "daily_p_ele_num",
"name": "日峰用电", "name": "日峰用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "daily_v_ele_num", "key": "daily_v_ele_num",
"name": "日谷用电", "name": "日谷用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "daily_n_ele_num", "key": "daily_n_ele_num",
"name": "日平用电", "name": "日平用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "daily_t_ele_num", "key": "daily_t_ele_num",
"name": "日尖用电", "name": "日尖用电",
"unit_of_measurement": UNIT_DU, "native_unit_of_measurement": UnitOfEnergy.KILO_WATT_HOUR,
"native_unit_of_measurement": UNIT_DU "device_class": SensorDeviceClass.ENERGY,
"state_class": SensorStateClass.TOTAL
}, },
{ {
"key": "daily_lasted_date", "key": "daily_lasted_date",
"name": "最新用电日期" "name": "最新用电日期"
}, },
{ {
"key": "refresh_time", "key": "refresh_time",
@@ -132,10 +174,11 @@ SENSOR_TYPES_FOR_LADDER = [
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
) -> None: ) -> None:
coordinator = StateGridCoordinator(hass)
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() coordinator = StateGridCoordinator(hass)
data_client.coordinator = coordinator
await coordinator.async_config_entry_first_refresh()
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, sensor_type, entry.entry_id, coordinator) for sensor_type in SENSOR_TYPES] [StateGridSensor(door_account, sensor_type, entry.entry_id, coordinator) for sensor_type in SENSOR_TYPES]
@@ -161,6 +204,12 @@ class StateGridSensor(CoordinatorEntity[StateGridCoordinator], SensorEntity):
self._attr_unique_id = entry_id + "-" + door_account["consNo_dst"] + "-" + sensor_type["key"] 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: if "native_unit_of_measurement" in sensor_type:
self._attr_native_unit_of_measurement = sensor_type["native_unit_of_measurement"] self._attr_native_unit_of_measurement = sensor_type["native_unit_of_measurement"]
@@ -176,4 +225,4 @@ class StateGridSensor(CoordinatorEntity[StateGridCoordinator], SensorEntity):
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.sensor_type["key"]] return data[self.sensor_type["key"]]
+5
View File
@@ -0,0 +1,5 @@
{
"name": "state_grid",
"homeassistant": "2024.2.0",
"render_readme": true
}
-75
View File
@@ -1,75 +0,0 @@
#!/bin/bash
# curl -fsSL get.hassbox.cn/state_grid | bash
set -e
export LC_ALL=en_US.UTF-8
RED_COLOR='\033[0;31m'
GREEN_COLOR='\033[0;32m'
GREEN_YELLOW='\033[1;33m'
NO_COLOR='\033[0m'
declare haPath
declare -a paths=(
"$PWD"
"$PWD/config"
"/config"
"$HOME/.homeassistant"
"/usr/share/hassio/homeassistant"
)
function info () { echo -e "${GREEN_COLOR}INFO: $1${NO_COLOR}";}
function warn () { echo -e "${GREEN_YELLOW}WARN: $1${NO_COLOR}";}
function error () { echo -e "${RED_COLOR}ERROR: $1${NO_COLOR}";}
function checkRequirement () {
if [ -z "$(command -v "$1")" ]; then
warn "'$1' 未安装,准备安装..."
apt install $1
fi
}
info "检查依赖项"
checkRequirement "wget"
checkRequirement "unzip"
for path in "${paths[@]}"; do
if [ -n "$haPath" ]; then
break
fi
if [ -f "$path/.HA_VERSION" ]; then
haPath="$path"
fi
done
if [ -z "$haPath" ]; then
echo
error "找不到 Home Assistant 根目录"
exit 1
fi
cd "$haPath"
if [ ! -d "$haPath/custom_components" ]; then
mkdir "$haPath/custom_components"
fi
cd "$haPath/custom_components"
info "检查依赖项 ok"
info "下载 state_grid 集成包"
wget "https://get.hasss.cn/state_grid.zip" >/dev/null 2>&1
info "下载 HassBox 集成包 ok"
info "state_grid 集成包解压"
if [ -d "$haPath/custom_components/state_grid" ]; then
rm -R "$haPath/custom_components/state_grid"
fi
mkdir "$haPath/custom_components/state_grid"
unzip "$haPath/custom_components/state_grid.zip" -d "$haPath/custom_components/state_grid" >/dev/null 2>&1
rm "$haPath/custom_components/state_grid.zip"
info "HassBox 集成包解压 ok"
info "安装成功!请重启 Home Assistant!如需其他帮助,可至 HassBox全屋智能 微信公众号联系客服"