Skip to content

Commit

Permalink
fix: fix logging in to electrolux, store auth token between restarts,…
Browse files Browse the repository at this point in the history
… report unavailable appliances, fix carbon dioxide alert level
  • Loading branch information
tomekkleszcz committed Mar 1, 2024
1 parent e68f96d commit e5c4c86
Show file tree
Hide file tree
Showing 11 changed files with 7,563 additions and 770 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"files.eol": "\n",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"editor.rulers": [140],
"eslint.enable": true,
Expand Down
2,055 changes: 1,323 additions & 732 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"displayName": "Homebridge Electrolux Devices",
"name": "homebridge-electrolux-devices",
"version": "0.0.3",
"version": "0.0.5",
"description": "Homebridge plugin for Electrolux devices",
"license": "Apache-2.0",
"repository": {
Expand All @@ -12,11 +12,12 @@
"url": "https://github.com/tomekkleszcz/homebridge-electrolux-devices/issues"
},
"engines": {
"node": ">=14.18.1",
"homebridge": ">=1.3.5"
"node": "^18.17.0 || ^20.9.0",
"homebridge": "^1.6.0"
},
"main": "dist/index.js",
"scripts": {
"postinstall": "patch-package",
"lint": "eslint src/**.ts --max-warnings=0",
"watch": "npm run build && npm link && nodemon",
"build": "rimraf ./dist && tsc",
Expand All @@ -30,6 +31,7 @@
"gigya": "^3.0.1",
"js-base64": "^3.7.5",
"lodash": "^4.17.21",
"patch-package": "^8.0.0",
"qs": "^6.11.2",
"strict-uri-encode": "^2.0.0"
},
Expand All @@ -38,7 +40,7 @@
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1",
"homebridge": "^1.3.5",
"homebridge": "^1.6.0",
"nodemon": "^2.0.20",
"rimraf": "^3.0.2",
"ts-node": "^10.3.0",
Expand Down
5,939 changes: 5,939 additions & 0 deletions patches/gigya+3.0.1.patch

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/accessories/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export abstract class ElectroluxAccessoryController {

async sendCommand(body: Record<string, CharacteristicValue>): Promise<void> {
try {
if(Date.now() >= this.platform.tokenExpirationDate) {
if(this.platform.tokenExpirationDate && Date.now() >= this.platform.tokenExpirationDate) {
await this.platform.refreshAccessToken();
}

Expand Down
98 changes: 97 additions & 1 deletion src/accessories/devices/airPurifier/airPurifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ElectroluxAccessoryController } from '../../controller';
export class AirPurifier extends ElectroluxAccessoryController {

private airPurifierService: Service;
private ionizerService: Service;
private airQualityService: Service;
private humiditySensorService: Service;
private temperatureSensorService: Service;
Expand Down Expand Up @@ -49,6 +50,15 @@ export class AirPurifier extends ElectroluxAccessoryController {
.onGet(this.getRotationSpeed.bind(this))
.onSet(this.setRotationSpeed.bind(this));

this.ionizerService = this.accessory.getService(this.platform.Service.Switch) ||
this.accessory.addService(this.platform.Service.Switch);

this.ionizerService.setCharacteristic(this.platform.Characteristic.Name, 'Ionizer');

this.ionizerService.getCharacteristic(this.platform.Characteristic.On)
.onGet(this.getIonizer.bind(this))
.onSet(this.setIonizer.bind(this));

this.airQualityService = this.accessory.getService(this.platform.Service.AirQualitySensor) ||
this.accessory.addService(this.platform.Service.AirQualitySensor);

Expand Down Expand Up @@ -78,17 +88,25 @@ export class AirPurifier extends ElectroluxAccessoryController {
}

async getActive(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.Workmode === 'PowerOff' ?
this.platform.Characteristic.Active.INACTIVE :
this.platform.Characteristic.Active.ACTIVE;
}

async setActive(value: CharacteristicValue) {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

if(
this.appliance.properties.reported.Workmode === 'PowerOff' && value === this.platform.Characteristic.Active.ACTIVE ||
this.appliance.properties.reported.Workmode !== 'PowerOff' && value === this.platform.Characteristic.Active.INACTIVE
) {
this.sendCommand({
await this.sendCommand({
'Workmode': value === this.platform.Characteristic.Active.ACTIVE ? 'Auto' : 'PowerOff'
});

Expand All @@ -101,6 +119,7 @@ export class AirPurifier extends ElectroluxAccessoryController {
this.platform.Characteristic.TargetAirPurifierState.AUTO
);


this.airPurifierService.updateCharacteristic(
this.platform.Characteristic.RotationSpeed,
value === this.platform.Characteristic.Active.ACTIVE ? this.appliance.properties.reported.Fanspeed : 0);
Expand All @@ -115,6 +134,10 @@ export class AirPurifier extends ElectroluxAccessoryController {
}

async getCurrentAirPurifierState(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

switch(this.appliance.properties.reported.Workmode) {
case 'Manual':
return this.platform.Characteristic.CurrentAirPurifierState.PURIFYING_AIR;
Expand All @@ -126,6 +149,10 @@ export class AirPurifier extends ElectroluxAccessoryController {
}

async getTargetAirPurifierState(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

switch(this.appliance.properties.reported.Workmode) {
case 'Manual':
return this.platform.Characteristic.TargetAirPurifierState.MANUAL;
Expand All @@ -137,6 +164,10 @@ export class AirPurifier extends ElectroluxAccessoryController {
}

async setTargetAirPurifierState(value: CharacteristicValue) {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

let workMode;
switch(value) {
case this.platform.Characteristic.TargetAirPurifierState.MANUAL:
Expand All @@ -155,12 +186,20 @@ export class AirPurifier extends ElectroluxAccessoryController {
}

async getLockPhysicalControls(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.SafetyLock ?
this.platform.Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED :
this.platform.Characteristic.LockPhysicalControls.CONTROL_LOCK_DISABLED;
}

async setLockPhysicalControls(value: CharacteristicValue) {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

await this.sendCommand({
'SafetyLock': value === this.platform.Characteristic.LockPhysicalControls.CONTROL_LOCK_ENABLED
});
Expand All @@ -169,10 +208,18 @@ export class AirPurifier extends ElectroluxAccessoryController {
}

async getRotationSpeed(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.Fanspeed * 20;
}

async setRotationSpeed(value: CharacteristicValue) {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

if(this.appliance.properties.reported.Workmode === 'Auto') {
setTimeout(() => {
this.airPurifierService.updateCharacteristic(
Expand Down Expand Up @@ -207,7 +254,31 @@ export class AirPurifier extends ElectroluxAccessoryController {
this.appliance.properties.reported.Fanspeed = Math.round((value as number) / 20);
}

async getIonizer(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.Ionizer;
}

async setIonizer(value: CharacteristicValue) {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

await this.sendCommand({
'Ionizer': value
});

this.appliance.properties.reported.Ionizer = value as boolean;
}

async getAirQuality(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

if(this.appliance.properties.reported.PM2_5 <= 25) {
return this.platform.Characteristic.AirQuality.EXCELLENT;
} else if(this.appliance.properties.reported.PM2_5 <= 50) {
Expand All @@ -222,23 +293,43 @@ export class AirPurifier extends ElectroluxAccessoryController {
}

async getPM2_5Density(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.PM2_5;
}

async getPM10Density(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.PM10;
}

async getVOCDensity(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.TVOC;
}


async getCurrentRelativeHumidity(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.Humidity;
}

async getCurrentTemperature(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.Temp;
}

Expand Down Expand Up @@ -301,6 +392,11 @@ export class AirPurifier extends ElectroluxAccessoryController {
this.appliance.properties.reported.Fanspeed * 20
);

this.ionizerService.updateCharacteristic(
this.platform.Characteristic.On,
this.appliance.properties.reported.Ionizer ? 1 : 0
);

this.airQualityService.updateCharacteristic(
this.platform.Characteristic.AirQuality,
await this.getAirQuality()
Expand Down
12 changes: 10 additions & 2 deletions src/accessories/devices/airPurifier/pureA9.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,25 @@ export class PureA9 extends AirPurifier {
}

async getCarbonDioxideDetected(): Promise<CharacteristicValue> {
return this.appliance.properties.reported.ECO2 > 1000 ?
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.ECO2 > this.platform.config.carbonDioxideSensorAlarmValue ?
this.platform.Characteristic.CarbonDioxideDetected.CO2_LEVELS_ABNORMAL :
this.platform.Characteristic.CarbonDioxideDetected.CO2_LEVELS_NORMAL;
}

async getCarbonDioxideLevel(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.ECO2;
}

async update(appliance: Appliance) {
this.appliance = appliance;
super.update(appliance);

this.carbonDioxideSensorService.updateCharacteristic(
this.platform.Characteristic.CarbonDioxideDetected, this.appliance.properties.reported.CO2 > this.platform.config.carbonDioxideSensorAlarmValue ?
Expand Down
12 changes: 10 additions & 2 deletions src/accessories/devices/airPurifier/wellA7.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,25 @@ export class WellA7 extends AirPurifier {
}

async getCarbonDioxideDetected(): Promise<CharacteristicValue> {
return this.appliance.properties.reported.ECO2 > 1000 ?
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.ECO2 > this.platform.config.carbonDioxideSensorAlarmValue ?
this.platform.Characteristic.CarbonDioxideDetected.CO2_LEVELS_ABNORMAL :
this.platform.Characteristic.CarbonDioxideDetected.CO2_LEVELS_NORMAL;
}

async getCarbonDioxideLevel(): Promise<CharacteristicValue> {
if(this.appliance.connectionState === 'Disconnected') {
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}

return this.appliance.properties.reported.ECO2;
}

async update(appliance: Appliance) {
this.appliance = appliance;
super.update(appliance);

this.carbonDioxideSensorService.updateCharacteristic(
this.platform.Characteristic.CarbonDioxideDetected, this.appliance.properties.reported.ECO2 > this.platform.config.carbonDioxideSensorAlarmValue ?
Expand Down
Loading

0 comments on commit e5c4c86

Please sign in to comment.