Skip to content

Commit

Permalink
Refactored blinds handling (#47)
Browse files Browse the repository at this point in the history
* Fix and refactor blinds handling

* Fix initial position

* Fix position stare

* Use internal device properties and update it with position

* Other fixes

* Fix position state

* Fix position from time: set min and max

* Major refactoring

* Fix missing setPosition call

* Fix test
Fix timeout before stopping

* No extra time

* Fix test
  • Loading branch information
madchicken authored Sep 4, 2021
1 parent c2b9e69 commit 8776949
Show file tree
Hide file tree
Showing 16 changed files with 2,475 additions and 462 deletions.
36 changes: 17 additions & 19 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
module.exports = {
env: {
browser: false,
es6: true
es6: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended"
],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/eslint-recommended'],
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly"
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parser: "@typescript-eslint/parser",
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: "module"
sourceType: 'module',
},
plugins: ["@typescript-eslint"],
plugins: ['@typescript-eslint'],
rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
vars: "all",
args: "after-used",
ignoreRestSiblings: false
}
]
}
vars: 'all',
args: 'after-used',
argsIgnorePattern: '^_',
ignoreRestSiblings: false,
},
],
},
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/node_modules/
.idea
.npmrc
/coverage/
21 changes: 19 additions & 2 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@
"placeholder": ""
}
},
"blind_opening_time": {
"title": "Time spent by the blind to get fully open from closed position (default 37 seconds)",
"type": "number",
"required": false,
"default": 37
},
"blind_closing_time": {
"title": "Time spent by the blind to get fully closed from open position (default 35 seconds)",
"title": "Time spent by the blind to get fully closed from opened position (default 35 seconds)",
"type": "number",
"required": false,
"default": 35
Expand All @@ -68,6 +74,12 @@
"type": "boolean",
"default": false
},
"use_comelit_blind_timing": {
"title": "Use open/close time configured in Comelit HUB for all standard blinds",
"description": "If this is set to true, the opening and closing time for each blind are read from internal Comelit configuration (you can use official Comelit app to change them). This settings overrides global opening and closing time settings. Does not affect new blinds with position support",
"type": "boolean",
"default": false
},
"hide_lights": {
"title": "Avoid mapping lights",
"type": "boolean",
Expand Down Expand Up @@ -112,6 +124,12 @@
"title": "Main settings",
"items": ["name", "username", "password", "broker_url"]
},
{
"type": "fieldset",
"expandable": false,
"title": "Blinds settings",
"items": ["use_comelit_blind_timing", "blind_opening_time", "blind_closing_time"]
},
{
"type": "fieldset",
"expandable": true,
Expand All @@ -120,7 +138,6 @@
"items": [
"hub_username",
"hub_password",
"blind_closing_time",
"keep_alive",
"avoid_duplicates",
"hide_lights",
Expand Down
7 changes: 7 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// eslint-disable-next-line no-undef
module.exports = {
verbose: true,
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/__tests__/**/*.test.ts'],
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
},
"dependencies": {
"async-mqtt": "2.6.1",
"comelit-client": "2.3.3",
"comelit-client": "2.3.5",
"express": "^4.17.1",
"fakegato-history": "^0.6.1",
"lodash": "4.17.21",
Expand All @@ -62,6 +62,7 @@
"homebridge": "^1.3.1",
"husky": "^4.2.3",
"jest": "^24.9.0",
"ts-jest": "^26.4.4",
"nock": "^12.0.2",
"prettier": "^1.19.1",
"pretty-quick": "^2.0.1",
Expand Down
190 changes: 190 additions & 0 deletions src/accessories/__tests__/blinds.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import { StandardBlind } from '../standard-blind';
import { ComelitPlatform, HubConfig } from '../../comelit-platform';
import { HomebridgeAPI } from 'homebridge/lib/api';
import { withPrefix } from 'homebridge/lib/logger';
import { Categories } from 'homebridge';
import { BlindDeviceData, ComelitClient } from 'comelit-client';
import { PositionState } from '../hap';
import { EnhancedBlind } from '../enhanced-blind';
import { getPositionAsByte } from '../../utils';
import { Blind } from '../blind';

const STD_BLIND_DEVICE_DATA: BlindDeviceData = {
id: 'DOM#BL#19.1',
type: 2,
sub_type: 7,
descrizione: 'Tapparella destra',
sched_status: '0',
sched_lock: '1970-01-01 01:00:00',
status: '0',
powerst: '0',
open_status: '1',
num_modulo: '19',
num_uscita: '1',
openTime: '60',
closeTime: '60',
preferPosition: '',
enablePreferPosition: '0',
icon_id: '0',
isProtected: '0',
objectId: 'DOM#BL#19.1',
placeId: 'GEN#PL#258',
};

const ENHANCED_BLIND_DEVICE_DATA: BlindDeviceData = {
id: 'DOM#BL#32.1',
type: 2,
sub_type: 31,
descrizione: 'Soggiorno',
sched_status: '0',
sched_lock: '1970-01-01 01:00:00',
status: '0',
powerst: '0',
position: '255',
open_status: '0',
preferPosition: '127',
enablePreferPosition: '1',
num_modulo: '32',
num_uscita: '1',
openTime: '40',
closeTime: '37',
icon_id: '2',
isProtected: '0',
objectId: 'DOM#BL#32.1',
placeId: 'GEN#PL#221',
};

jest.useFakeTimers();

jest.mock('comelit-client', () => {
return {
ComelitClient: jest.fn().mockImplementation(() => {
return { toggleDeviceStatus: jest.fn(), setBlindPosition: jest.fn() };
}),
};
});

const config: HubConfig = {
platform: 'comelit',
username: 'string',
password: 'string',
hub_username: 'string',
hub_password: 'string',
};

describe('Blinds', () => {
it('should update std blind status', async () => {
const api = new HomebridgeAPI();
const platform = new ComelitPlatform(withPrefix('test'), config, api);
const accessory = platform.createHapAccessory(
STD_BLIND_DEVICE_DATA,
Categories.WINDOW_COVERING,
STD_BLIND_DEVICE_DATA.id
);
const client = new ComelitClient(() => jest.fn());
const blind = new StandardBlind(platform, accessory, client);
const service = accessory.getService(platform.Service.WindowCovering);
const targetPosition = service.getCharacteristic(platform.Characteristic.TargetPosition);
const positionState = service.getCharacteristic(platform.Characteristic.PositionState);
const position = service.getCharacteristic(platform.Characteristic.CurrentPosition);

expect(targetPosition.value).toBe(Blind.OPEN);
expect(position.value).toBe(Blind.OPEN);
expect(positionState.value).toBe(PositionState.STOPPED);

await blind.setPosition(40, jest.fn);
expect(client.toggleDeviceStatus).toHaveBeenCalledTimes(1);
expect(client.toggleDeviceStatus).toHaveBeenCalledWith(STD_BLIND_DEVICE_DATA.id, 0);
blind.updateDevice({
...STD_BLIND_DEVICE_DATA,
type: 2,
sub_type: 7,
sched_status: '0',
sched_lock: '1970-01-01 01:00:00',
status: '2',
powerst: '2',
open_status: '1',
});
expect(setTimeout).toHaveBeenLastCalledWith(
expect.any(Function),
((Blind.CLOSING_TIME * 1000) / 100) * 60
);
expect(positionState.value).toBe(PositionState.DECREASING);
// @ts-ignore
client.toggleDeviceStatus.mockClear();
jest.runAllTimers();
expect(client.toggleDeviceStatus).toHaveBeenCalledTimes(1);
expect(client.toggleDeviceStatus).toHaveBeenCalledWith(STD_BLIND_DEVICE_DATA.id, 1);
blind.updateDevice({
...STD_BLIND_DEVICE_DATA,
type: 2,
sub_type: 7,
sched_status: '0',
sched_lock: '1970-01-01 01:00:00',
status: '0',
powerst: '0',
open_status: '1',
});
expect(positionState.value).toBe(PositionState.STOPPED);
});

it('should update enhanced blind status', async () => {
const api = new HomebridgeAPI();
const platform = new ComelitPlatform(withPrefix('test'), config, api);
const accessory = platform.createHapAccessory(
ENHANCED_BLIND_DEVICE_DATA,
Categories.WINDOW_COVERING,
ENHANCED_BLIND_DEVICE_DATA.id
);
const client = new ComelitClient(() => jest.fn());
const blind = new EnhancedBlind(platform, accessory, client);
const service = accessory.getService(platform.Service.WindowCovering);
const positionState = service.getCharacteristic(platform.Characteristic.PositionState);
const targetPosition = service.getCharacteristic(platform.Characteristic.TargetPosition);
const position = service.getCharacteristic(platform.Characteristic.CurrentPosition);

expect(targetPosition.value).toBe(Blind.CLOSED);
expect(position.value).toBe(Blind.CLOSED);
expect(positionState.value).toBe(PositionState.STOPPED);

const callback = jest.fn;
await blind.setPosition(40, callback);
expect(client.setBlindPosition).toHaveBeenCalledTimes(1);
// expect(callback).toHaveBeenCalledTimes(1);
expect(client.setBlindPosition).toHaveBeenCalledWith(
ENHANCED_BLIND_DEVICE_DATA.id,
getPositionAsByte(40)
);
expect(targetPosition.value).toBe(40);
blind.updateDevice({
...ENHANCED_BLIND_DEVICE_DATA,
type: 2,
sub_type: 31,
sched_status: '0',
sched_lock: '1970-01-01 01:00:00',
status: '1',
powerst: '1',
position: '255',
open_status: '0',
preferPosition: '127',
enablePreferPosition: '1',
});
expect(positionState.value).toBe(PositionState.INCREASING);
blind.updateDevice({
...ENHANCED_BLIND_DEVICE_DATA,
type: 2,
sub_type: 31,
sched_status: '0',
sched_lock: '1970-01-01 01:00:00',
status: '0',
powerst: '1',
position: `${getPositionAsByte(40)}`,
open_status: '0',
preferPosition: '127',
enablePreferPosition: '1',
});

expect(positionState.value).toBe(PositionState.STOPPED);
expect(position.value).toBe(40);
});
});
3 changes: 0 additions & 3 deletions src/accessories/__tests__/thermostat.test.ts

This file was deleted.

Loading

0 comments on commit 8776949

Please sign in to comment.