Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ The following endpoints (according to ...) are currently not implemented and ca
* /aircon/get_day_paower_ex

## Changelog
### __WORK IN PROGRESS__
* (@lleonis) Add support for mompow (momentary power consumption) sensor field and expose value in Watts

### 2.2.2 (2025-05-25)
* (@Matze2) Handles potential error case when using demand control data

Expand Down
13 changes: 13 additions & 0 deletions src/DaikinAC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export class DaikinAC {
if (this._updateCallback) this._updateCallback(err);
return;
}

this.getACDemandControl((err, _info) => {
this.initUpdateTimeout();
if (err && this._logger) {
Expand Down Expand Up @@ -230,6 +231,18 @@ export class DaikinAC {
if (this._logger) this._logger(JSON.stringify(daikinResponse));
this._currentACSensorInfo = daikinResponse;

// Apply high-level logic: set mompow to 0 when AC is powered off
// Only apply this if we have control info available
if (
!err &&
daikinResponse &&
this._currentACControlInfo &&
this._currentACControlInfo.power === false &&
daikinResponse.mompow !== undefined
) {
daikinResponse.mompow = 0;
}

if (callback) callback(err, daikinResponse);
});
}
Expand Down
11 changes: 11 additions & 0 deletions src/models/responses/SensorInfoResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export class SensorInfoResponse {
public outdoorTemperature?: number;
public error?: number;
public cmpfreq?: number;
public mompow?: number;

public static parseResponse(dict: ResponseDict, cb: DaikinResponseCb<SensorInfoResponse>): void {
const result = new SensorInfoResponse();
Expand All @@ -15,6 +16,16 @@ export class SensorInfoResponse {
result.outdoorTemperature = DaikinDataParser.resolveFloat(dict, 'otemp');
result.error = DaikinDataParser.resolveInteger(dict, 'err');
result.cmpfreq = DaikinDataParser.resolveInteger(dict, 'cmpfreq');

// Parse mompow field and convert from 0.1kW units to Watts
const rawMompow = DaikinDataParser.resolveInteger(dict, 'mompow');
if (typeof rawMompow === 'number') {
// Convert mompow from 0.1kW units to Watts by multiplying by 100
result.mompow = rawMompow * 100;
} else {
result.mompow = undefined;
}

cb(null, 'OK', result);
}
}
15 changes: 10 additions & 5 deletions test/testDaikinAC.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ describe('Test DaikinAC', () => {
'ret=OK,pow=0,mode=3,adv=,stemp=23.0,shum=0,dt1=25.0,dt2=M,dt3=23.0,dt4=27.0,dt5=27.0,dt7=25.0,dh1=AUTO,dh2=50,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=50,b_mode=3,b_stemp=23.0,b_shum=0,alert=255,f_rate=3,f_dir=0,b_f_rate=A,b_f_dir=0,dfr1=5,dfr2=5,dfr3=A,dfr4=5,dfr5=5,dfr6=5,dfr7=5,dfrh=5,dfd1=0,dfd2=0,dfd3=0,dfd4=0,dfd5=0,dfd6=0,dfd7=0,dfdh=0',
)
.get('/aircon/get_sensor_info')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0,mompow=150')
.get('/aircon/get_demand_control')
.replyWithError('Not supported')
.get('/aircon/get_control_info')
.reply(
200,
'ret=OK,pow=0,mode=3,adv=,stemp=24.0,shum=0,dt1=25.0,dt2=M,dt3=23.0,dt4=27.0,dt5=27.0,dt7=25.0,dh1=AUTO,dh2=50,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=50,b_mode=3,b_stemp=23.0,b_shum=0,alert=255,f_rate=A,f_dir=0,b_f_rate=A,b_f_dir=0,dfr1=5,dfr2=5,dfr3=A,dfr4=5,dfr5=5,dfr6=5,dfr7=5,dfrh=5,dfd1=0,dfd2=0,dfd3=0,dfd4=0,dfd5=0,dfd6=0,dfd7=0,dfdh=0',
)
.get('/aircon/get_sensor_info')
.reply(200, 'ret=OK,htemp=22.5,hhum=-,otemp=-,err=0,cmpfreq=0');
.reply(200, 'ret=OK,htemp=22.5,hhum=-,otemp=-,err=0,cmpfreq=0,mompow=200');
const daikin = new DaikinAC('127.0.0.1', options, function (err) {
expect(err).toBeNull();
expect(daikin.currentCommonBasicInfo).not.toBeNull();
Expand All @@ -75,20 +77,22 @@ describe('Test DaikinAC', () => {
expect(daikin.currentACControlInfo!.targetTemperature).toEqual(23);
expect(daikin.currentACControlInfo!.fanRate).toEqual(3);
expect(daikin.currentACSensorInfo!.indoorTemperature).toEqual(21.5);
expect(daikin.currentACSensorInfo!.mompow).toEqual(0);
} else {
expect(cnt).toEqual(2);
expect(daikin.currentACControlInfo).not.toBeNull();
expect(daikin.currentACSensorInfo).not.toBeNull();
expect(daikin.currentACControlInfo!.targetTemperature).toEqual(24);
expect(daikin.currentACControlInfo!.fanRate).toEqual('A');
expect(daikin.currentACSensorInfo!.indoorTemperature).toEqual(22.5);
expect(daikin.currentACSensorInfo!.mompow).toEqual(0);
daikin.stopUpdate();
expect(req.isDone()).toBeTruthy();
expect(daikin.updateTimeout).toBeNull();
expect(daikin.currentACControlInfo).not.toBeNull();
expect(daikin.currentACSensorInfo).not.toBeNull();
expect(Object.keys(daikin.currentACControlInfo!).length).toEqual(42);
expect(Object.keys(daikin.currentACSensorInfo!).length).toEqual(5);
expect(Object.keys(daikin.currentACSensorInfo!).length).toEqual(6);
done();
}
});
Expand Down Expand Up @@ -191,7 +195,7 @@ describe('Test DaikinAC', () => {
.get('/aircon/get_remote_method')
.reply(200, 'ret=OK,method=home only,notice_ip_int=3600,notice_sync_int=60')
.get('/aircon/get_sensor_info')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0,mompow=300')
.get('/aircon/get_model_info')
.reply(200, 'ret=OK,model=NOTSUPPORT,type=N,pv=0,cpv=0,mid=NA,s_fdir=1,en_scdltmr=1')
.get('/aircon/get_week_power')
Expand Down Expand Up @@ -235,9 +239,10 @@ describe('Test DaikinAC', () => {

daikin.getACSensorInfo(function (err, response) {
expect(err).toBeNull();
expect(Object.keys(response!).length).toEqual(5);
expect(Object.keys(response!).length).toEqual(6);
expect(response!.indoorTemperature).toEqual(21.5);
expect(response!.outdoorTemperature).toBeNaN();
expect(response!.mompow).toEqual(30000);

daikin.getACModelInfo(function (err, response) {
expect(err).toBeNull();
Expand Down
53 changes: 48 additions & 5 deletions test/testDaikinACGet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ describe('Test DaikinAC', function () {
'ret=OK,pow=0,mode=3,adv=,stemp=23.0,shum=0,dt1=25.0,dt2=M,dt3=23.0,dt4=27.0,dt5=27.0,dt7=25.0,dh1=AUTO,dh2=50,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=50,b_mode=3,b_stemp=23.0,b_shum=0,alert=255,f_rate=A,f_dir=0,b_f_rate=A,b_f_dir=0,dfr1=5,dfr2=5,dfr3=A,dfr4=5,dfr5=5,dfr6=5,dfr7=5,dfrh=5,dfd1=0,dfd2=0,dfd3=0,dfd4=0,dfd5=0,dfd6=0,dfd7=0,dfdh=0',
)
.get('/aircon/get_sensor_info?lpw=')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0,mompow=150')
.get('/aircon/get_demand_control?lpw=')
.replyWithError('Not supported')
.get('/aircon/get_control_info?lpw=')
.reply(
200,
'ret=OK,pow=0,mode=3,adv=,stemp=24.0,shum=0,dt1=25.0,dt2=M,dt3=23.0,dt4=27.0,dt5=27.0,dt7=25.0,dh1=AUTO,dh2=50,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=50,b_mode=3,b_stemp=23.0,b_shum=0,alert=255,f_rate=A,f_dir=0,b_f_rate=A,b_f_dir=0,dfr1=5,dfr2=5,dfr3=A,dfr4=5,dfr5=5,dfr6=5,dfr7=5,dfrh=5,dfd1=0,dfd2=0,dfd3=0,dfd4=0,dfd5=0,dfd6=0,dfd7=0,dfdh=0',
)
.get('/aircon/get_sensor_info?lpw=')
.reply(200, 'ret=OK,htemp=22.5,hhum=-,otemp=-,err=0,cmpfreq=0');
.reply(200, 'ret=OK,htemp=22.5,hhum=-,otemp=-,err=0,cmpfreq=0,mompow=200');
const daikin = new DaikinAC('127.0.0.1', options, function (err) {
expect(err).toBeNull();
expect(Object.keys(daikin.currentCommonBasicInfo!).length).toEqual(25);
Expand All @@ -72,15 +74,17 @@ describe('Test DaikinAC', function () {
if (cnt == 1) {
expect(daikin.currentACControlInfo!.targetTemperature).toEqual(23);
expect(daikin.currentACSensorInfo!.indoorTemperature).toEqual(21.5);
expect(daikin.currentACSensorInfo!.mompow).toEqual(0);
} else {
expect(cnt).toEqual(2);
expect(daikin.currentACControlInfo!.targetTemperature).toEqual(24);
expect(daikin.currentACSensorInfo!.indoorTemperature).toEqual(22.5);
expect(daikin.currentACSensorInfo!.mompow).toEqual(0);
daikin.stopUpdate();
expect(req.isDone()).toBeTruthy();
expect(daikin.updateTimeout).toBeNull();
expect(Object.keys(daikin.currentACControlInfo!).length).toEqual(42);
expect(Object.keys(daikin.currentACSensorInfo!).length).toEqual(5);
expect(Object.keys(daikin.currentACSensorInfo!).length).toEqual(6);
done();
}
});
Expand Down Expand Up @@ -183,7 +187,7 @@ describe('Test DaikinAC', function () {
.get('/aircon/get_remote_method?lpw=')
.reply(200, 'ret=OK,method=home only,notice_ip_int=3600,notice_sync_int=60')
.get('/aircon/get_sensor_info?lpw=')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0,mompow=300')
.get('/aircon/get_model_info?lpw=')
.reply(200, 'ret=OK,model=NOTSUPPORT,type=N,pv=0,cpv=0,mid=NA,s_fdir=1,en_scdltmr=1')
.get('/aircon/get_week_power?lpw=')
Expand Down Expand Up @@ -227,9 +231,10 @@ describe('Test DaikinAC', function () {

daikin.getACSensorInfo(function (err, response) {
expect(err).toBeNull();
expect(Object.keys(response!).length).toEqual(5);
expect(Object.keys(response!).length).toEqual(6);
expect(response!.indoorTemperature).toEqual(21.5);
expect(response!.outdoorTemperature).toBeNaN();
expect(response!.mompow).toEqual(30000);

daikin.getACModelInfo(function (err, response) {
expect(err).toBeNull();
Expand Down Expand Up @@ -293,4 +298,42 @@ describe('Test DaikinAC', function () {
});
});
}, 600000);

it('power state logic test - mompow=0 when pow=0', function (done) {
const req = nock('http://127.0.0.1')
.get('/common/basic_info')
.reply(
200,
'ret=OK,type=aircon,reg=eu,dst=1,ver=2_6_0,pow=0,err=0,location=0,name=%4b%6c%69%6d%61%20%4a%61%6e%61,icon=0,method=home only,port=30050,id=,pw=,lpw_flag=1,adp_kind=2,pv=0,cpv=0,cpv_minor=00,led=0,en_setzone=1,mac=A408EACC91D4,adp_mode=run,en_hol=0,grp_name=%4b%69%6e%64%65%72,en_grp=1',
)
.get('/aircon/get_model_info?lpw=')
.reply(200, 'ret=OK,model=NOTSUPPORT,type=N,pv=0,cpv=0,mid=NA,s_fdir=1,en_scdltmr=1')
.get('/aircon/get_control_info?lpw=')
.reply(
200,
'ret=OK,pow=0,mode=3,adv=,stemp=23.0,shum=0,dt1=25.0,dt2=M,dt3=23.0,dt4=27.0,dt5=27.0,dt7=25.0,dh1=AUTO,dh2=50,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=50,b_mode=3,b_stemp=23.0,b_shum=0,alert=255,f_rate=A,f_dir=0,b_f_rate=A,b_f_dir=0,dfr1=5,dfr2=5,dfr3=A,dfr4=5,dfr5=5,dfr6=5,dfr7=5,dfrh=5,dfd1=0,dfd2=0,dfd3=0,dfd4=0,dfd5=0,dfd6=0,dfd7=0,dfdh=0',
)
.get('/aircon/get_sensor_info?lpw=')
.reply(200, 'ret=OK,htemp=21.5,hhum=-,otemp=-,err=0,cmpfreq=0,mompow=1');
const daikin = new DaikinAC('127.0.0.1', options, function (err) {
expect(err).toBeNull();

// First get control info to load power state
daikin.getACControlInfo(function (err, controlResponse) {
expect(err).toBeNull();
expect(controlResponse!.power).toBeFalsy(); // Verify AC is off

// Then get sensor info to test power state logic
daikin.getACSensorInfo(function (err, response) {
expect(err).toBeNull();
expect(Object.keys(response!).length).toEqual(6);
expect(response!.indoorTemperature).toEqual(21.5);
expect(response!.mompow).toEqual(0); // Should be 0 due to power state logic even though device reports 1

expect(req.isDone()).toBeTruthy();
done();
});
});
});
});
});
Loading