Skip to content

Commit

Permalink
Add Diffuser support (xxj). (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
0x5e authored Dec 26, 2022
1 parent 40e0c0f commit 9db1e48
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Add Camera support (`sp`). Thanks @ErrorErrorError for the contribution
- Add Air Conditioner support (`kt`). (#160)
- Add Air Conditioner Controller support (`ktkzq`). (#160)
- Add Diffuser support (`xxj`).


### Fixed
Expand Down
2 changes: 1 addition & 1 deletion SUPPORTED_DEVICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Most category code is pinyin abbreviation of Chinese name.
| Heater | 取暖器 | qn | Heater Coller ||
| Air Purifier | 空气净化器 | kj | Air Purifier ||
| Drying Rack | 晾衣架 | lyj | | |
| Diffuser | 香薰机 | xxj | | |
| Diffuser | 香薰机 | xxj | Air Purifier, Lightbulb | |
| Curtain | 窗帘 | cl | Window Covering ||
| Door and Window Controller | 门窗控制器 | mc | Window ||
| Thermostat | 温控器 | wk | Thermostat ||
Expand Down
4 changes: 4 additions & 0 deletions src/accessory/AccessoryFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import AirQualitySensorAccessory from './AirQualitySensorAccessory';
import HumanPresenceSensorAccessory from './HumanPresenceSensorAccessory';
import HumidifierAccessory from './HumidifierAccessory';
import DehumidifierAccessory from './DehumidifierAccessory';
import DiffuserAccessory from './DiffuserAccessory';
import AirPurifierAccessory from './AirPurifierAccessory';
import TemperatureHumidityIRSensorAccessory from './TemperatureHumidityIRSensorAccessory';
import CameraAccessory from './CameraAccessory';
Expand Down Expand Up @@ -142,6 +143,9 @@ export default class AccessoryFactory {
case 'cs':
handler = new DehumidifierAccessory(platform, accessory);
break;
case 'xxj':
handler = new DiffuserAccessory(platform, accessory);
break;
case 'kt':
case 'ktkzq':
handler = new AirConditionerAccessory(platform, accessory);
Expand Down
126 changes: 126 additions & 0 deletions src/accessory/DiffuserAccessory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { TuyaDeviceSchemaIntegerProperty, TuyaDeviceStatus } from '../device/TuyaDevice';
import { limit, remap } from '../util/util';
import BaseAccessory from './BaseAccessory';
import { configureOn } from './characteristic/On';
import { configureRotationSpeedLevel } from './characteristic/RotationSpeed';

const SCHEMA_CODE = {
ON: ['switch'],
SPRAY_ON: ['switch_spray'],
SPRAY_MODE: ['mode'],
SPRAY_LEVEL: ['level'],
LIGHT_ON: ['switch_led'],
LIGHT_MODE: ['work_mode'],
LIGHT_BRIGHTNESS: ['bright_value', 'bright_value_v2'],
LIGHT_COLOR: ['colour_data_hsv'],
SOUND_ON: ['switch_sound'],
};

export default class DiffuserAccessory extends BaseAccessory {

requiredSchema() {
return [SCHEMA_CODE.ON, SCHEMA_CODE.SPRAY_ON];
}

configureServices() {
configureOn(this, undefined, this.getSchema(...SCHEMA_CODE.ON)); // Main Switch
this.configureAirPurifier();
this.configureLight();
configureOn(this, undefined, this.getSchema(...SCHEMA_CODE.SOUND_ON)); // Sound Switch
}

configureAirPurifier() {
const onSchema = this.getSchema(...SCHEMA_CODE.ON)!;
const sprayOnSchema = this.getSchema(...SCHEMA_CODE.SPRAY_ON)!;

// Required Characteristics
const { INACTIVE, ACTIVE } = this.Characteristic.Active;
this.mainService().getCharacteristic(this.Characteristic.Active)
.onGet(() => {
return (this.getStatus(onSchema.code)!.value && this.getStatus(sprayOnSchema.code)!.value) ? ACTIVE : INACTIVE;
})
.onSet(value => {
const commands = [{ code: sprayOnSchema.code, value: (value === ACTIVE) }];
if (value === ACTIVE) {
commands.push({ code: onSchema.code, value: true });
}
this.sendCommands(commands, true);
});

const { PURIFYING_AIR } = this.Characteristic.CurrentAirPurifierState;
this.mainService().getCharacteristic(this.Characteristic.CurrentAirPurifierState)
.onGet(() => {
return (this.getStatus(onSchema.code)!.value && this.getStatus(sprayOnSchema.code)!.value) ? PURIFYING_AIR : INACTIVE;
});

// const { MANUAL } = this.Characteristic.TargetAirPurifierState;
// this.mainService().getCharacteristic(this.Characteristic.TargetAirPurifierState)
// .setProps({ validValues: [MANUAL] });


// Optional Characteristics
configureRotationSpeedLevel(this, this.mainService(), this.getSchema(...SCHEMA_CODE.SPRAY_LEVEL));
}

configureLight() {
const onSchema = this.getSchema(...SCHEMA_CODE.ON)!;
const lightOnSchema = this.getSchema(...SCHEMA_CODE.LIGHT_ON);
if (!lightOnSchema) {
return;
}

this.lightService().getCharacteristic(this.Characteristic.On)
.onGet(() => {
return this.getStatus(onSchema.code)!.value && this.getStatus(lightOnSchema.code)!.value;
})
.onSet(value => {
const commands = [{ code: lightOnSchema.code, value: value as boolean }];
if (value) {
commands.push({ code: onSchema.code, value: true });
}
this.sendCommands(commands, true);
});
this.configureLightBrightness();
}

mainService() {
return this.accessory.getService(this.Service.AirPurifier)
|| this.accessory.addService(this.Service.AirPurifier);
}

lightService() {
return this.accessory.getService(this.Service.Lightbulb)
|| this.accessory.addService(this.Service.Lightbulb, this.device.name + ' Light');
}

configureLightBrightness() {
const schema = this.getSchema(...SCHEMA_CODE.LIGHT_BRIGHTNESS);
if (!schema) {
return;
}

const lightModeSchema = this.getSchema(...SCHEMA_CODE.LIGHT_MODE);

const { min, max } = schema.property as TuyaDeviceSchemaIntegerProperty;
this.lightService().getCharacteristic(this.Characteristic.Brightness)
.onGet(() => {
const status = this.getStatus(schema.code)!;
const value = Math.round(remap(status.value as number, 0, max, 0, 100));
return limit(value, 0, 100);
})
.onSet(value => {
let brightness = Math.round(remap(value as number, 0, 100, 0, max));
brightness = limit(brightness, min, max);

const commands: TuyaDeviceStatus[] = [{
code: schema.code,
value: brightness,
}];

if (lightModeSchema) {
commands.push({ code: lightModeSchema.code, value: 'white' });
}
this.sendCommands(commands, true);
});
}
}
7 changes: 6 additions & 1 deletion src/accessory/characteristic/On.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import { Service } from 'homebridge';
import { TuyaDeviceSchema } from '../../device/TuyaDevice';
import BaseAccessory from '../BaseAccessory';

export function configureOn(accessory: BaseAccessory, service: Service, schema?: TuyaDeviceSchema) {
export function configureOn(accessory: BaseAccessory, service?: Service, schema?: TuyaDeviceSchema) {
if (!schema) {
return;
}

if (!service) {
service = accessory.accessory.getService(schema.code)
|| accessory.accessory.addService(accessory.Service.Switch, schema.code, schema.code);
}

service.getCharacteristic(accessory.Characteristic.On)
.onGet(() => {
const status = accessory.getStatus(schema.code)!;
Expand Down

0 comments on commit 9db1e48

Please sign in to comment.