@@ -2,7 +2,7 @@ import {Zcl} from "zigbee-herdsman";
22import * as exposes from "../lib/exposes" ;
33import * as m from "../lib/modernExtend" ;
44import * as tuya from "../lib/tuya" ;
5- import type { DefinitionWithExtend , Fz , ModernExtend , Tz } from "../lib/types" ;
5+ import type { DefinitionWithExtend , Fz , KeyValue , ModernExtend , Tz } from "../lib/types" ;
66
77const e = exposes . presets ;
88const ea = exposes . access ;
@@ -44,118 +44,6 @@ const localValueConverters = {
4444} ;
4545
4646const futurehomeExtend = {
47- chargerStatus1 : ( ) : ModernExtend => {
48- return {
49- isModernExtend : true ,
50- fromZigbee : [
51- {
52- cluster : "haApplianceControl" ,
53- type : [ "commandSignalStateNotification" , "commandSignalStateRsp" ] ,
54- convert ( model , msg , publish , options , meta ) {
55- const status = msg ?. data ?. applianceStatus ;
56- if ( status === undefined || status === null ) return ;
57- let chargerStatus :
58- | "plugged_out"
59- | "1X: Off"
60- | "4: plugged_in"
61- | "2: plugged_in_charging"
62- | "3: plugged_in_paused"
63- | "5X: running"
64- | "8X: failure" = "plugged_out" ;
65- let chargingOn = false ;
66-
67- switch ( status ) {
68- case 0x01 : // Off
69- chargerStatus = "1X: Off" ;
70- chargingOn = false ;
71- break ;
72- case 0x02 : // StandBy → charging
73- chargerStatus = "2: plugged_in_charging" ;
74- chargingOn = true ;
75- break ;
76- case 0x03 : // Programmed (paused by user)
77- chargerStatus = "3: plugged_in_paused" ;
78- chargingOn = false ;
79- break ;
80- case 0x04 : // ProgrammedWaitingToStart
81- chargerStatus = "4: plugged_in" ;
82- chargingOn = false ;
83- break ;
84- case 0x05 : // Running
85- chargerStatus = "5X: running" ;
86- chargingOn = false ;
87- break ;
88- case 0x08 : // Failure
89- chargerStatus = "8X: failure" ;
90- chargingOn = false ;
91- break ;
92- default :
93- chargerStatus = "plugged_out" ;
94- chargingOn = false ;
95- }
96- return { charger_status : chargerStatus , charging_on : chargingOn } ;
97- } ,
98- } satisfies Fz . Converter < "haApplianceControl" , undefined , [ "commandSignalStateNotification" , "commandSignalStateRsp" ] > ,
99- ] ,
100- toZigbee : [
101- {
102- key : [ "charger_status" ] ,
103- convertGet : async ( entity , key , meta ) => {
104- await entity . command ( "haApplianceControl" , "signalState" , { } ) ;
105- } ,
106- } satisfies Tz . Converter ,
107- ] ,
108- configure : [
109- async ( device , coordinatorEndpoint , logger ) => {
110- for ( const endpoint of device . endpoints ) {
111- if ( endpoint . supportsInputCluster ( "haApplianceControl" ) ) {
112- await endpoint . bind ( "haApplianceControl" , coordinatorEndpoint ) ;
113- try {
114- await endpoint . command ( "haApplianceControl" , "signalState" , { } ) ;
115- } catch {
116- // do nothing
117- }
118- }
119- }
120- } ,
121- ] ,
122- options : [
123- e
124- . numeric ( "charger_status_poll_interval" , ea . SET )
125- . withValueMin ( - 1 )
126- . withDescription ( "Polling interval charger status (default: 60s, -1 to disable)" ) ,
127- ] ,
128- onEvent : m . poll ( {
129- key : "charger_status_poll" ,
130- optionKey : "charger_status_poll_interval" ,
131- option : e
132- . numeric ( "charger_status_poll_interval" , ea . SET )
133- . withValueMin ( - 1 )
134- . withDescription ( "Polling interval charger status (default: 60s, -1 to disable)" ) ,
135- defaultIntervalSeconds : 60 ,
136- poll : async ( device ) => {
137- const endpoint = device . endpoints . find ( ( e ) => e . supportsInputCluster ( "haApplianceControl" ) ) ;
138- if ( endpoint ) {
139- await endpoint . command ( "haApplianceControl" , "signalState" , { } ) ;
140- }
141- } ,
142- } ) . onEvent ,
143- exposes : [
144- exposes
145- . enum ( "charger_status" , ea . STATE_GET , [
146- "plugged_out" ,
147- "1X: Off" ,
148- "2: plugged_in_charging" ,
149- "3: plugged_in_paused" ,
150- "4: plugged_in" ,
151- "5X: running" ,
152- "8X: failure" ,
153- ] )
154- . withDescription ( "Current EV charger state" ) ,
155- exposes . binary ( "charging_on" , ea . STATE , "true" , "false" ) . withDescription ( "Indicates if the charger is actively delivering power" ) ,
156- ] ,
157- } ;
158- } ,
15947 chargerStatus : ( ) : ModernExtend => {
16048 const extend : ModernExtend = {
16149 isModernExtend : true ,
@@ -168,7 +56,7 @@ const futurehomeExtend = {
16856 if ( status === undefined || status === null ) return ;
16957 let chargerStatus :
17058 | "plugged_out"
171- | "1X : Off"
59+ | "1 : Off"
17260 | "4: plugged_in"
17361 | "2: plugged_in_charging"
17462 | "3: plugged_in_paused"
@@ -178,7 +66,7 @@ const futurehomeExtend = {
17866
17967 switch ( status ) {
18068 case 0x01 : // Off
181- chargerStatus = "1X : Off" ;
69+ chargerStatus = "1 : Off" ;
18270 chargingOn = false ;
18371 break ;
18472 case 0x02 : // StandBy → charging
@@ -235,7 +123,7 @@ const futurehomeExtend = {
235123 exposes
236124 . enum ( "charger_status" , ea . STATE_GET , [
237125 "plugged_out" ,
238- "1X : Off" ,
126+ "1 : Off" ,
239127 "2: plugged_in_charging" ,
240128 "3: plugged_in_paused" ,
241129 "4: plugged_in" ,
@@ -309,33 +197,37 @@ const futurehomeExtend = {
309197 cluster : "haApplianceControl" ,
310198 type : [ "attributeReport" , "readResponse" ] ,
311199 convert : ( model , msg , publish , options , meta ) => {
312- // const prev_session_energy = (msg.data.energyMeterNow - msg.data.energyMeterStart) / 1000;
313- // if (msg.data.energyMeterNow !== undefined && msg.data.energyMeterStart !== undefined) {
314- // const prev_session_energy = msg.data.energyMeterNow - msg.data.energyMeterStart;
315- // return {
316- // previous_session_energy: prev_session_energy,
317- // };
318- // }
319- let start = meta . state ?. energy_meter_start !== undefined ? meta . state . energy_meter_start : null ;
320- let now = meta . state ?. energy_meter_now !== undefined ? meta . state . energy_meter_now : null ;
321- if ( Object . hasOwn ( msg . data , "energyMeterStart" ) ) {
322- start = msg . data . energyMeterStart / 1000 ;
200+ const result : KeyValue = { } ;
201+ let energyStart = meta . state ?. energy_meter_start !== undefined ? meta . state . energy_meter_start : null ;
202+ let energyNow = meta . state ?. energy_meter_now !== undefined ? meta . state . energy_meter_now : null ;
203+ let startT = meta . state ?. start_t !== undefined ? meta . state . start_t : null ;
204+ let endT = meta . state ?. end_t !== undefined ? meta . state . now_t : null ;
205+ if ( msg . data . energyMeterStart !== undefined ) {
206+ energyStart = msg . data . energyMeterStart / 1000 ;
207+ }
208+ if ( msg . data . energyMeterNow !== undefined ) {
209+ energyNow = msg . data . energyMeterNow / 1000 ;
323210 }
324- if ( Object . hasOwn ( msg . data , "energyMeterNow" ) ) {
325- now = msg . data . energyMeterNow / 1000 ;
211+ if ( msg . data . chargingSessionStartT !== undefined ) {
212+ startT = msg . data . chargingSessionStartT ;
326213 }
327- if ( start !== null && now !== null ) {
328- const consumed = ( now as number ) - ( start as number ) ;
329- return {
330- // toFixed(3) prevents floating-point precision issues in JavaScript (e.g., 0.300000000004)
331- session_energy : Number . parseFloat ( consumed . toFixed ( 3 ) ) ,
332- } ;
214+ if ( msg . data . chargingSessionEndT !== undefined ) {
215+ endT = msg . data . chargingSessionEndT ;
333216 }
334- return ;
217+ if ( energyStart !== null && energyNow !== null ) {
218+ result . session_energy = ( ( energyNow as number ) - ( energyStart as number ) ) . toFixed ( 3 ) ;
219+ }
220+ if ( startT !== null && endT !== null ) {
221+ result . charging_duration = ( endT as number ) - ( startT as number ) ;
222+ }
223+ return result ;
335224 } ,
336225 } satisfies Fz . Converter < "haApplianceControl" , FuturehomeHaApplianceControl , [ "attributeReport" , "readResponse" ] > ,
337226 ] ,
338- exposes : [ exposes . numeric ( "session_energy" , ea . STATE ) . withLabel ( "Session energy" ) . withDescription ( "Previous session" ) . withUnit ( "kWh" ) ] ,
227+ exposes : [
228+ exposes . numeric ( "session_energy" , ea . STATE ) . withLabel ( "Session energy" ) . withDescription ( "Previous session" ) . withUnit ( "kWh" ) ,
229+ exposes . numeric ( "charging_duration" , ea . STATE ) . withDescription ( "Charging duration last session" ) . withUnit ( "s" ) ,
230+ ] ,
339231 } ;
340232 } ,
341233} ;
@@ -597,7 +489,7 @@ export const definitions: DefinitionWithExtend[] = [
597489 attribute : "energyMeterStart" ,
598490 description : "energyMeterStart" ,
599491 unit : "kWh" ,
600- access : "STATE_GET " ,
492+ access : "STATE " ,
601493 scale : 1000 ,
602494 reporting : { min : 5 , max : "1_HOUR" , change : 1 } ,
603495 zigbeeCommandOptions : { manufacturerCode : Zcl . ManufacturerCode . FUTUREHOME_AS } ,
@@ -608,7 +500,7 @@ export const definitions: DefinitionWithExtend[] = [
608500 attribute : "energyMeterNow" ,
609501 description : "energyMeterNow" ,
610502 unit : "kWh" ,
611- access : "STATE_GET " ,
503+ access : "STATE " ,
612504 scale : 1000 ,
613505 reporting : { min : 5 , max : "1_HOUR" , change : 1 } ,
614506 zigbeeCommandOptions : { manufacturerCode : Zcl . ManufacturerCode . FUTUREHOME_AS } ,
@@ -620,6 +512,7 @@ export const definitions: DefinitionWithExtend[] = [
620512 description : "Status" ,
621513 lookup : {
622514 plugged_out : 0x00 ,
515+ off : 0x01 ,
623516 plugged_in_charging : 0x02 ,
624517 plugged_in_paused : 0x03 ,
625518 plugged_in : 0x04 ,
@@ -633,7 +526,7 @@ export const definitions: DefinitionWithExtend[] = [
633526 cluster : "haApplianceControl" ,
634527 attribute : "chargingSessionStartT" ,
635528 description : "Start time of charging session. Time in seconds. Should be converted to date and time." ,
636- access : "STATE_GET " ,
529+ access : "STATE " ,
637530 scale : 1.0 ,
638531 unit : "s" ,
639532 reporting : { min : 5 , max : "1_HOUR" , change : 1 } ,
@@ -644,7 +537,7 @@ export const definitions: DefinitionWithExtend[] = [
644537 cluster : "haApplianceControl" ,
645538 attribute : "chargingSessionEndT" ,
646539 description : "End time of charging session. Time in seconds. Should be converted to date and time." ,
647- access : "STATE_GET " ,
540+ access : "STATE " ,
648541 scale : 1.0 ,
649542 unit : "s" ,
650543 reporting : { min : 5 , max : "1_HOUR" , change : 1 } ,
0 commit comments