Skip to content

Commit

Permalink
fix #1093 - accessories display
Browse files Browse the repository at this point in the history
  • Loading branch information
oznu committed Feb 24, 2021
1 parent 7c504bd commit 725081b
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 184 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "homebridge-config-ui-x",
"displayName": "Homebridge UI",
"version": "4.39.1-test.4",
"version": "4.39.1-test.5",
"description": "A web based management, configuration and control platform for Homebridge",
"license": "MIT",
"author": "oznu <dev@oz.nu>",
Expand Down Expand Up @@ -57,7 +57,7 @@
"@nestjs/platform-socket.io": "7.6.5",
"@nestjs/swagger": "4.7.12",
"@nestjs/websockets": "7.6.5",
"@oznu/hap-client": "1.7.1",
"@oznu/hap-client": "1.7.2",
"axios": "0.21.1",
"class-transformer": "^0.3.2",
"class-validator": "^0.13.1",
Expand Down Expand Up @@ -151,4 +151,4 @@
"smart home",
"hb-service"
]
}
}
18 changes: 15 additions & 3 deletions src/modules/accessories/accessories.service.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import * as path from 'path';
import * as fs from 'fs-extra';
import * as NodeCache from 'node-cache';
import { Injectable, BadRequestException } from '@nestjs/common';
import { HapClient, ServiceType } from '@oznu/hap-client';

import { ConfigService } from '../../core/config/config.service';
import { Logger } from '../../core/logger/logger.service';

@Injectable()
export class AccessoriesService {
public hapClient: HapClient;
public accessoriesCache = new NodeCache({ stdTTL: 3600 });

constructor(
private readonly configService: ConfigService,
Expand All @@ -34,14 +37,23 @@ export class AccessoriesService {

let services;

const loadAllAccessories = async () => {
const loadAllAccessories = async (refresh: boolean) => {
if (!refresh) {
const cached = this.accessoriesCache.get<any[]>('services');
if (cached && cached.length) {
client.emit('accessories-data', cached);
}
}

services = await this.loadAccessories();
this.refreshCharacteristics(services);
client.emit('accessories-ready-for-control');
client.emit('accessories-data', services);
this.accessoriesCache.set('services', services);
};

// initial load
await loadAllAccessories();
await loadAllAccessories(false);

// handling incoming requests
const requestHandler = async (msg?) => {
Expand Down Expand Up @@ -77,7 +89,7 @@ export class AccessoriesService {

// load a second time in case anything was missed
const secondaryLoadTimeout = setTimeout(async () => {
await loadAllAccessories();
await loadAllAccessories(true);
}, 3000);

// clean up on disconnect
Expand Down
6 changes: 3 additions & 3 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@ng-bootstrap/ng-bootstrap": "^7.0.0",
"@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0",
"@oznu/hap-client": "^1.7.1",
"@oznu/hap-client": "^1.7.2",
"@oznu/ngx-bs4-jsonform": "^7.3.7",
"angular-gridster2": "^11.0.1",
"bootstrap": "^4.6.0",
Expand Down
44 changes: 3 additions & 41 deletions ui/src/app/core/accessories/accessories.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { HeaterCoolerComponent } from './types/heatercooler/heatercooler.compone
import { HeaterCoolerManageComponent } from './types/heatercooler/heatercooler.manage.component';

import { InfoModalComponent } from './info-modal/info-modal.component';
import { AccessoryTileComponent } from './accessory-tile/accessory-tile.component';

@NgModule({
entryComponents: [
Expand All @@ -71,6 +72,7 @@ import { InfoModalComponent } from './info-modal/info-modal.component';
HeaterCoolerManageComponent,
],
declarations: [
AccessoryTileComponent,
InfoModalComponent,
SwitchComponent,
StatelessprogrammableswitchComponent,
Expand Down Expand Up @@ -126,47 +128,7 @@ import { InfoModalComponent } from './info-modal/info-modal.component';
CoreModule,
],
exports: [
SwitchComponent,
StatelessprogrammableswitchComponent,
ThermostatComponent,
ThermostatManageComponent,
OutletComponent,
FanComponent,
FanManageComponent,
Fanv2Component,
Fanv2ManageComponent,
UnknownComponent,
LightbulbComponent,
LightbulbManageComponent,
LightsensorComponent,
LockmechanismComponent,
TemperaturesensorComponent,
GaragedooropenerComponent,
MotionsensorComponent,
OccupancysensorComponent,
HumiditysensorComponent,
AirqualitysensorComponent,
WindowcoveringComponent,
WindowcoveringManageComponent,
WindowComponent,
WindowManageComponent,
DoorComponent,
DoorManageComponent,
TelevisionComponent,
ContactsensorComponent,
BatteryserviceComponent,
SpeakerComponent,
SpeakerManageComponent,
SecuritysystemComponent,
SecuritysystemManageComponent,
LeaksensorComponent,
ValveComponent,
ValveManageComponent,
IrrigationSystemComponent,
AirpurifierComponent,
AirpurifierManageComponent,
HeaterCoolerComponent,
HeaterCoolerManageComponent,
AccessoryTileComponent,
],
providers: [
AccessoriesService,
Expand Down
62 changes: 38 additions & 24 deletions ui/src/app/core/accessories/accessories.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export class AccessoriesService {
public layoutSaved = new Subject();
public accessoryData = new Subject();

public readyForControl = false;

public accessoryLayout: {
name: string; services: Array<{
aid: number;
Expand Down Expand Up @@ -51,6 +53,8 @@ export class AccessoriesService {
* Start the accessory control session
*/
public async start() {
this.readyForControl = false;

// connect to the socket endpoint
this.io = this.$ws.connectToNamespace('accessories');

Expand Down Expand Up @@ -95,6 +99,12 @@ export class AccessoriesService {
this.io.socket.on('accessory-control-failure', (message) => {
this.$toastr.error(message);
});

// when the system is ready for accessory control
this.io.socket.on('accessories-ready-for-control', (message) => {
console.log('ready for control');
this.readyForControl = true;
});
}

/**
Expand All @@ -105,9 +115,9 @@ export class AccessoriesService {

// build empty room layout
this.rooms = this.accessoryLayout.map((room) => ({
name: room.name,
services: [],
}));
name: room.name,
services: [],
}));
}

/**
Expand Down Expand Up @@ -226,17 +236,17 @@ export class AccessoriesService {
public saveLayout() {
// generate layout schema to save to disk
this.accessoryLayout = this.rooms.map((room) => ({
name: room.name,
services: room.services.map((service) => ({
uniqueId: service.uniqueId,
aid: service.aid,
iid: service.iid,
uuid: service.uuid,
customName: service.customName || undefined,
hidden: service.hidden || undefined,
onDashboard: service.onDashboard || undefined,
})),
})).filter(room => room.services.length);
name: room.name,
services: room.services.map((service) => ({
uniqueId: service.uniqueId,
aid: service.aid,
iid: service.iid,
uuid: service.uuid,
customName: service.customName || undefined,
hidden: service.hidden || undefined,
onDashboard: service.onDashboard || undefined,
})),
})).filter(room => room.services.length);

// send update request to server
this.io.request('save-layout', { user: this.$auth.user.username, layout: this.accessoryLayout })
Expand All @@ -261,17 +271,21 @@ export class AccessoriesService {
}

characteristic.setValue = (value: number | string | boolean) => new Promise((resolve, reject) => {
this.io.socket.emit('accessory-control', {
set: {
uniqueId: service.uniqueId,
aid: service.aid,
siid: service.iid,
iid: characteristic.iid,
value,
},
});
return resolve();
if (!this.readyForControl) {
resolve(undefined);
}

this.io.socket.emit('accessory-control', {
set: {
uniqueId: service.uniqueId,
aid: service.aid,
siid: service.iid,
iid: characteristic.iid,
value,
},
});
return resolve(undefined);
});

return characteristic;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<ng-container [ngSwitch]="service.type">
<i class="fas fa-cog manage-accessory-button primary-text" (click)="$accessories.showAccessoryInformation(service)"
*ngIf="$accessories.readyForControl"></i>
<i class="fas fa-spin fa-sync-alt refreshing-accessory-status-icon text-grey" *ngIf="!$accessories.readyForControl">

</i>
<app-switch *ngSwitchCase="'Switch'" [service]="service">Switch</app-switch>
<app-thermostat *ngSwitchCase="'Thermostat'" [service]="service">Thermostat</app-thermostat>
<app-outlet *ngSwitchCase="'Outlet'" [service]="service">Outlet</app-outlet>
<app-fan *ngSwitchCase="'Fan'" [service]="service" class="w-100">Fan</app-fan>
<app-fanv2 *ngSwitchCase="'Fanv2'" [service]="service" class="w-100">Fan</app-fanv2>
<app-airpurifier *ngSwitchCase="'AirPurifier'" [service]="service" class="w-100">Air Purifier
</app-airpurifier>
<app-lightbulb *ngSwitchCase="'Lightbulb'" [service]="service">Lightbulb</app-lightbulb>
<app-lightsensor *ngSwitchCase="'LightSensor'" [service]="service">Light Sensor
</app-lightsensor>
<app-lockmechanism *ngSwitchCase="'LockMechanism'" [service]="service">Lock Mechanism</app-lockmechanism>
<app-temperaturesensor *ngSwitchCase="'TemperatureSensor'" [service]="service">Temperature Sensor
</app-temperaturesensor>
<app-garagedooropener *ngSwitchCase="'GarageDoorOpener'" [service]="service">Garage Door Opener
</app-garagedooropener>
<app-motionsensor *ngSwitchCase="'MotionSensor'" [service]="service">Motion Sensor</app-motionsensor>
<app-occupancysensor *ngSwitchCase="'OccupancySensor'" [service]="service">Occupancy Sensor
</app-occupancysensor>
<app-contactsensor *ngSwitchCase="'ContactSensor'" [service]="service">Contact Sensor
</app-contactsensor>
<app-humiditysensor *ngSwitchCase="'HumiditySensor'" [service]="service">Humidity Sensor
</app-humiditysensor>
<app-airqualitysensor *ngSwitchCase="'AirQualitySensor'" [service]="service">Air Quality Sensor
</app-airqualitysensor>
<app-windowcovering *ngSwitchCase="'WindowCovering'" [service]="service">Window Covering
</app-windowcovering>
<app-window *ngSwitchCase="'Window'" [service]="service">Window
</app-window>
<app-door *ngSwitchCase="'Door'" [service]="service">Door
</app-door>
<app-television *ngSwitchCase="'Television'" [service]="service">Television
</app-television>
<app-batteryservice *ngSwitchCase="'BatteryService'" [service]="service">BatteryService
</app-batteryservice>
<app-speaker *ngSwitchCase="'Speaker'" [service]="service">Speaker</app-speaker>
<app-securitysystem *ngSwitchCase="'SecuritySystem'" [service]="service">Security System
</app-securitysystem>
<app-leaksensor *ngSwitchCase="'LeakSensor'" [service]="service">Leak Sensor
</app-leaksensor>
<app-valve *ngSwitchCase="'Valve'" [service]="service">Valve
</app-valve>
<app-irrigationsystem *ngSwitchCase="'IrrigationSystem'" [service]="service">Irrigation System
</app-irrigationsystem>
<app-heatercooler *ngSwitchCase="'HeaterCooler'" [service]="service">Heater Cooler
</app-heatercooler>
<app-statelessprogrammableswitch *ngSwitchCase="'StatelessProgrammableSwitch'" [service]="service">
Stateless Programmable Switch
</app-statelessprogrammableswitch>
<app-unknown *ngSwitchDefault [service]="service">{{ service.humanType }}</app-unknown>
</ng-container>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Component, Input, OnInit } from '@angular/core';
import { ServiceTypeX } from '../accessories.interfaces';
import { AccessoriesService } from '../accessories.service';

@Component({
selector: 'app-accessory-tile',
templateUrl: './accessory-tile.component.html',
styleUrls: ['./accessory-tile.component.scss'],
})
export class AccessoryTileComponent implements OnInit {
@Input() public service: ServiceTypeX;

constructor(
public $accessories: AccessoriesService,
) { }

ngOnInit(): void {
}

}
Loading

0 comments on commit 725081b

Please sign in to comment.