Skip to content

Commit

Permalink
added feature to clear cached accessories when using hb-service
Browse files Browse the repository at this point in the history
  • Loading branch information
oznu committed Feb 2, 2020
1 parent c036566 commit 4b1b3d2
Show file tree
Hide file tree
Showing 29 changed files with 277 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. This projec
* **Plugins:** Added an option to have a plugin's config removed from the `config.json` when the plugin is being uninstalled (only plugins that implement the [Plugins Settings GUI](https://github.com/oznu/homebridge-config-ui-x/wiki/Developers:-Plugin-Settings-GUI) support this feature)
* **Dashboard:** Weather widget now supports local translations of the current weather description ([#515](https://github.com/oznu/homebridge-config-ui-x/issues/515))
* **System:** The UI will now attempt to rebuild it's own modules after a Node.js upgrade
* **System:** Added the ability for [`hb-service`](https://github.com/oznu/homebridge-config-ui-x/wiki/Homebridge-Service-Command) users to clear the Homebridge cached accessories from the UI (without doing a full hard reset)

### Other Changes

Expand Down
2 changes: 1 addition & 1 deletion 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 package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "homebridge-config-ui-x",
"displayName": "Homebridge Config UI X",
"version": "4.10.0-beta.2",
"version": "4.10.0-beta.3",
"description": "A web based management, configuration and control platform for Homebridge",
"license": "MIT",
"author": "oznu <dev@oz.nu>",
Expand Down
36 changes: 36 additions & 0 deletions src/bin/hb-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class HomebridgeServiceHelper {
private log: fs.WriteStream;
private homebridgeBinary: string;
private homebridge: child_process.ChildProcessWithoutNullStreams;
private homebridgeStopped = true;
private homebridgeOpts = [];
private homebridgeCustomEnv = {};
private uiBinary: string;
Expand Down Expand Up @@ -258,6 +259,12 @@ export class HomebridgeServiceHelper {
this.startExitHandler();
this.runHomebridge();
this.runUi();

process.addListener('message', (event) => {
if (event === 'clearCachedAccessories') {
this.clearHomebridgeCachedAccessories();
}
});
}

/**
Expand Down Expand Up @@ -286,6 +293,8 @@ export class HomebridgeServiceHelper {
* Starts homebridge as a child process, sending the log output to the homebridge.log
*/
private runHomebridge() {
this.homebridgeStopped = false;

if (this.homebridgeOpts.length) {
this.logger(`Starting Homebridge with extra flags: ${this.homebridgeOpts.join(' ')}`);
}
Expand Down Expand Up @@ -337,6 +346,7 @@ export class HomebridgeServiceHelper {
* @param signal
*/
private handleHomebridgeClose(code: number, signal: string) {
this.homebridgeStopped = true;
this.logger(`Homebridge Process Ended. Code: ${code}, Signal: ${signal}`);
setTimeout(() => {
this.logger('Restarting Homebridge...');
Expand Down Expand Up @@ -590,6 +600,32 @@ export class HomebridgeServiceHelper {
}
}

/**
* Clears the Homebridge Cached Accessories
*/
private clearHomebridgeCachedAccessories() {
const cachedAccessoriesPath = path.resolve(this.storagePath, 'accessories', 'cachedAccessories');

const clearAccessoriesCache = () => {
try {
if (fs.existsSync(cachedAccessoriesPath)) {
this.logger('Clearing Cached Homebridge Accessories...');
fs.unlinkSync(cachedAccessoriesPath);
}
} catch (e) {
this.logger(`ERROR: Failed to clear Homebridge Accessories Cache at ${cachedAccessoriesPath}`);
console.error(e);
}
};

if (this.homebridge && !this.homebridgeStopped) {
this.homebridge.once('close', clearAccessoriesCache);
this.homebridge.kill();
} else {
clearAccessoriesCache();
}
}

}

function bootstrap() {
Expand Down
6 changes: 6 additions & 0 deletions src/modules/server/server.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ export class ServerController {
return this.serverService.resetHomebridgeAccessory();
}

@UseGuards(AdminGuard)
@Put('/reset-cached-accessories')
resetCachedAccessories() {
return this.serverService.resetCachedAccessories();
}

}
13 changes: 13 additions & 0 deletions src/modules/server/server.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ export class ServerService {
this.logger.log(`Homebridge Reset: "accessories" directory removed.`);
}

/**
* Clears the Homebridge Accessory Cache
*/
public async resetCachedAccessories() {
if (this.configService.serviceMode) {
this.logger.warn('Sent request to clear cached accesories to hb-service');
process.emit('message', 'clearCachedAccessories', undefined);
} else {
this.logger.error('The reset accessories cache command is only available in service mode');
throw new BadRequestException('This command is only available in service mode');
}
}

/**
* Returns a QR Code SVG
*/
Expand Down
3 changes: 3 additions & 0 deletions ui/src/app/core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { HrefTargetBlankDirective } from './directives/href-target-blank.directi
import { LongClickDirective } from './directives/longclick.directive';
import { ResetHomebridgeModalComponent } from './reset-homebridge-modal/reset-homebridge-modal.component';
import { TranslateModule } from '@ngx-translate/core';
import { ResetCachedAccessoriesModalComponent } from './reset-cached-accessories-modal/reset-cached-accessories-modal.component';

@NgModule({
entryComponents: [
ResetHomebridgeModalComponent,
ResetCachedAccessoriesModalComponent,
],
declarations: [
SpinnerComponent,
Expand All @@ -19,6 +21,7 @@ import { TranslateModule } from '@ngx-translate/core';
HrefTargetBlankDirective,
LongClickDirective,
ResetHomebridgeModalComponent,
ResetCachedAccessoriesModalComponent,
],
imports: [
CommonModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" [translate]="'reset.title_clear_cached_accessories'">Clear Cached Accessories</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"
(click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h3 class="text-center primary-text" [translate]="'reset.title_warning'">Warning</h3>
<p class="text-center grey-text" [translate]="'reset.message_action_is_irreversible'">This action is irreversible.
Please read carefully before proceeding.</p>
<ul>
<li [translate]="'reset.message_remove_cached_accessories'">
This action will remove all cached accessories from your Homebridge instance.
</li>
<li [translate]="'reset.accessories_will_may_need_to_be_reconfigured'">
After performing this action some accessories may need to be reconfigured in HomeKit or re-added to your
automations.
</li>
</ul>
<div class="text-center">
<button type="button" class="btn btn-elegant" data-dismiss="modal" (click)="onResetCachedAccessoriesClick()"
[disabled]="clicked" [translate]="'reset.title_clear_cached_accessories'">Clear Cached Accessories</button>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal" (click)="activeModal.dismiss('Cross click')"
[translate]="'form.button_close'">Close</button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { ToastrService } from 'ngx-toastr';
import { ApiService } from '../api.service';

@Component({
selector: 'app-reset-cached-accessories-modal',
templateUrl: './reset-cached-accessories-modal.component.html',
styleUrls: ['./reset-cached-accessories-modal.component.scss'],
})
export class ResetCachedAccessoriesModalComponent {
public clicked: boolean;

constructor(
public activeModal: NgbActiveModal,
public toastr: ToastrService,
private translate: TranslateService,
private $route: Router,
private $api: ApiService,
) { }

onResetCachedAccessoriesClick() {
this.clicked = true;
return this.$api.put('/server/reset-cached-accessories', {}).subscribe(
data => {
this.toastr.success(this.translate.instant('reset.toast_clear_cached_accessories_success'), this.translate.instant('toast.title_success'));
this.activeModal.close();
},
async err => {
this.toastr.error(this.translate.instant('reset.toast_failed_to_reset'), this.translate.instant('toast.title_error'));
},
);
}
}
30 changes: 30 additions & 0 deletions ui/src/app/modules/settings/settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,34 @@ <h5 class="primary-text">Environment Variables</h5>
</ul>
</div>

<div class="mt-3" *ngIf="$auth.env.serviceMode">
<h5 class="primary-text">Actions</h5>

<ul class="list-group mt-2">
<li class="list-group-item d-flex justify-content-between align-items-center">
<span>
{{ 'reset.title_clear_cached_accessories' | translate }}
<i class="fas fa-info-circle primary-text"
ngbTooltip="{{ 'reset.message_remove_cached_accessories' | translate }}"></i>
</span>
<button class="btn btn-primary waves-effect m-0" [translate]="'reset.title_clear_cached_accessories'"
(click)="resetCachedAccessories()">
{{ 'reset.title_clear_cache' | translate }}
</button>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<span>
{{ 'reset.title_reset_homebridge_accessory' | translate | titlecase }}
<i class="fas fa-info-circle primary-text"
ngbTooltip="{{ 'reset.message_reset_will_unpair_from_homekit' | translate }}"></i>
</span>
<button class="btn btn-primary waves-effect m-0" [translate]="'reset.title_clear_cached_accessories'"
(click)="resetHomebridgeState()">
{{ 'reset.title_reset' | translate }}
</button>
</li>
</ul>

</div>

</form>
18 changes: 17 additions & 1 deletion ui/src/app/modules/settings/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { FormGroup, FormBuilder } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { ActivatedRoute } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { debounceTime } from 'rxjs/operators';

import { AuthService } from '../../core/auth/auth.service';
import { ApiService } from '../../core/api.service';
import { debounceTime } from 'rxjs/operators';
import { ResetCachedAccessoriesModalComponent } from '../../core/reset-cached-accessories-modal/reset-cached-accessories-modal.component';
import { ResetHomebridgeModalComponent } from '../../core/reset-homebridge-modal/reset-homebridge-modal.component';

@Component({
selector: 'app-settings',
Expand All @@ -22,6 +25,7 @@ export class SettingsComponent implements OnInit {
private $api: ApiService,
public $fb: FormBuilder,
public $toastr: ToastrService,
private $modal: NgbModal,
private $route: ActivatedRoute,
private translate: TranslateService,
) { }
Expand Down Expand Up @@ -86,5 +90,17 @@ export class SettingsComponent implements OnInit {
});
}

resetHomebridgeState() {
this.$modal.open(ResetHomebridgeModalComponent, {
size: 'lg',
});
}

resetCachedAccessories() {
this.$modal.open(ResetCachedAccessoriesModalComponent, {
size: 'lg',
});
}


}
6 changes: 6 additions & 0 deletions ui/src/i18n/bg.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,23 @@
"plugins.status_update_available": "Налична е актуализация",
"plugins.toast_failed_to_load_plugins": "Неуспешно зареждане на добавките",
"plugins.tooltip_update_plugin_to": "Актуализирай добавката до v{{latestVersion}}",
"reset.accessories_will_may_need_to_be_reconfigured": "After performing this action some accessories may need to be reconfigured in HomeKit or re-added to your automations.",
"reset.button_reset_homebridge_now": "Нулирай Homebridge сега",
"reset.label_reset_homebridge": "Нулирай homebridge",
"reset.message_accessory_config_will_not_be_changed": "Останалата част от конфигурацията ви няма да бъде променена. Ако Homebridge не се стартира поради лоша конфигурация, нулирането няма да го поправи.",
"reset.message_action_is_irreversible": "Това действие е необратимо. Моля, прочетете внимателно, преди да продължите.",
"reset.message_all_automations_will_be_reset": "Всички автоматизации и ще трябва да бъдат пренастроени след нулиране.",
"reset.message_need_to_remove_homebridge_accessory_from_home_app": "Ще трябва да премахнете съществуващия Homebridge аксесоар ръчно от приложението Home.",
"reset.message_remove_cached_accessories": "This action will remove all cached accessories from your Homebridge instance.",
"reset.message_reset_will_unpair_from_homekit": "Нулирането ще раздвои тази инсталация на Homebridge от вашата настройка на Apple HomeKit.",
"reset.message_your_homebridge_username_will_be_changed": "Вашите Homebridge потребителско име и pin ще бъдат променени.",
"reset.title_clear_cache": "Clear Cache",
"reset.title_clear_cached_accessories": "Clear Cached Accessories",
"reset.title_reset": "Reset",
"reset.title_reset_homebridge_accessory": "Нулирай Homebridge аксесоар",
"reset.title_warning": "Внимание",
"reset.toast_accessory_reset": "Нулиране на аксесоар за Homebridge",
"reset.toast_clear_cached_accessories_success": "Restarting Homebridge and clearing accessory cache.",
"reset.toast_failed_to_reset": "Неуспешно нулиране на Homebridge. Виж лог.",
"restart.label_restart_command_executed": "Командата за рестартиране е изпълнена",
"restart.message_please_wait_while_server_restarts": "Моля, изчакайте, тази страница автоматично ще се пренасочи, когато сървърът отново е онлайн.",
Expand Down
6 changes: 6 additions & 0 deletions ui/src/i18n/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,23 @@
"plugins.status_update_available": "Aktualizace k dispozici",
"plugins.toast_failed_to_load_plugins": "Nepodařilo se načíst pluginy",
"plugins.tooltip_update_plugin_to": "Aktualizovat plugin pro v{{latestVersion}}",
"reset.accessories_will_may_need_to_be_reconfigured": "After performing this action some accessories may need to be reconfigured in HomeKit or re-added to your automations.",
"reset.button_reset_homebridge_now": "Resetovat Homebridge nyní",
"reset.label_reset_homebridge": "restartovat homebridge",
"reset.message_accessory_config_will_not_be_changed": "Zbytek konfigurace se nezmění. Pokud se Homebridge nespustí kvůli špatné konfiguraci, reset ji neopraví.",
"reset.message_action_is_irreversible": "Tato akce je nevratná. Před pokračováním prosím pečlivě přečtěte.",
"reset.message_all_automations_will_be_reset": "Všechny automatizace budou muset po restartování znovu nastaveny.",
"reset.message_need_to_remove_homebridge_accessory_from_home_app": "Budete muset ručně odstranit existující příslušenství Homebridge v aplikaci Domácnost.",
"reset.message_remove_cached_accessories": "This action will remove all cached accessories from your Homebridge instance.",
"reset.message_reset_will_unpair_from_homekit": "Reset odpáruje tento Homebridge most z vašeho nastavení Apple HomeKit.",
"reset.message_your_homebridge_username_will_be_changed": "Vaše Homebridge uživatelské jméno a PIN budou změněny.",
"reset.title_clear_cache": "Clear Cache",
"reset.title_clear_cached_accessories": "Clear Cached Accessories",
"reset.title_reset": "Reset",
"reset.title_reset_homebridge_accessory": "Resetovat příslušenství Homebridge",
"reset.title_warning": "Varování",
"reset.toast_accessory_reset": "Resetování příslušenství Homebridge",
"reset.toast_clear_cached_accessories_success": "Restarting Homebridge and clearing accessory cache.",
"reset.toast_failed_to_reset": "Resetování Homebridge se nezdařilo. Viz log.",
"restart.label_restart_command_executed": "Příkaz restartování spuštěn",
"restart.message_please_wait_while_server_restarts": "Čekejte prosím, tato stránka se automaticky přesměruje, když bude server znovu online.",
Expand Down
6 changes: 6 additions & 0 deletions ui/src/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,23 @@
"plugins.status_update_available": "Aktualisierung verfügbar",
"plugins.toast_failed_to_load_plugins": "Fehler beim Laden der Plugins",
"plugins.tooltip_update_plugin_to": "Plugin auf v{{latestVersion}} aktualisieren",
"reset.accessories_will_may_need_to_be_reconfigured": "After performing this action some accessories may need to be reconfigured in HomeKit or re-added to your automations.",
"reset.button_reset_homebridge_now": "Homebridge zurücksetzen",
"reset.label_reset_homebridge": "Homebridge zurücksetzen",
"reset.message_accessory_config_will_not_be_changed": "Die Konfiguration wird nicht geändert. Wenn Homebridge aufgrund einer fehlerhaften Konfiguration nicht gestartet wird, kann ein Reset das Problem <strong>nicht</strong> beheben.",
"reset.message_action_is_irreversible": "Diese Aktion ist nicht umkehrbar. Bitte prüfe sie sorgfältig, bevor du fortfährst.",
"reset.message_all_automations_will_be_reset": "Alle Automatisierungen müssen nach einem Reset neu konfiguriert werden.",
"reset.message_need_to_remove_homebridge_accessory_from_home_app": "Du musst das vorhandene Homebridge-Geräte manuell aus der Home-App entfernen.",
"reset.message_remove_cached_accessories": "This action will remove all cached accessories from your Homebridge instance.",
"reset.message_reset_will_unpair_from_homekit": "Durch einen Reset wird diese Homebridge-Instanz von deinem Apple HomeKit-Setup getrennt.",
"reset.message_your_homebridge_username_will_be_changed": "Dein Homebridge-Benutzername und Deine PIN werden geändert.",
"reset.title_clear_cache": "Clear Cache",
"reset.title_clear_cached_accessories": "Clear Cached Accessories",
"reset.title_reset": "Reset",
"reset.title_reset_homebridge_accessory": "Zurücksetzen der Homebridge-Geräte",
"reset.title_warning": "Warnung",
"reset.toast_accessory_reset": "Homebridge-Geräte zurücksetzen",
"reset.toast_clear_cached_accessories_success": "Restarting Homebridge and clearing accessory cache.",
"reset.toast_failed_to_reset": "Homebridge konnte nicht zurückgesetzt werden. Siehe Protokoll.",
"restart.label_restart_command_executed": "Neustart angestoßen",
"restart.message_please_wait_while_server_restarts": "Bitte warte, du wirst automatisch umgeleitet, wenn der Server wieder online ist.",
Expand Down
Loading

0 comments on commit 4b1b3d2

Please sign in to comment.