Skip to content

Commit

Permalink
Merge pull request #14 from justjam2013/create-json-classes
Browse files Browse the repository at this point in the history
Adding classes for json config and log to abstract class
  • Loading branch information
justjam2013 authored Nov 14, 2024
2 parents 5bb23e2 + 11a246b commit c530811
Show file tree
Hide file tree
Showing 22 changed files with 545 additions and 151 deletions.
2 changes: 1 addition & 1 deletion config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
"pattern": "^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])$"
},
"failureRetryCount": {
"title": "Retries Before Faillure",
"title": "Retries Before Failure *",
"description": "Failed ping count before triggering the sensor",
"type": "number",
"minimum": 0
Expand Down
29 changes: 26 additions & 3 deletions package-lock.json

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

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "homebridge-virtual-accessories",
"displayName": "Virtual Accessories for Homebridge",
"type": "module",
"version": "1.0.0-beta.7",
"version": "1.0.0-beta.8",
"description": "Virtual accessories for Homebridge.",
"author": "justjam2013",
"license": "Apache-2.0",
Expand Down Expand Up @@ -51,7 +51,9 @@
"@js-joda/core": "^5.6.3",
"@js-joda/timezone": "^2.21.1",
"cron": "^3.1.9",
"net-ping": "^1.2.4"
"net-ping": "^1.2.4",
"reflect-metadata": "^0.2.2",
"typeserializer": "^0.2.5"
},
"devDependencies": {
"@eslint/js": "^9.14.0",
Expand Down
32 changes: 15 additions & 17 deletions src/accessories/virtualAccessory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { VirtualSensor } from '../sensors/virtualSensor.js';
import { Timer } from '../timer.js';

import fs from 'fs';
import { AccessoryConfiguration } from '../configuration/configurationAccessory.js';

/**
* Virtual Accessory
* Abstract superclass for all virtual accessories and place to store common functionality
* Abstract Accessory
*/
export abstract class VirtualAccessory {
export abstract class Accessory {
service?: Service;

readonly platform: VirtualAccessoryPlatform;
Expand All @@ -19,11 +19,9 @@ export abstract class VirtualAccessory {
readonly CLOSED_NORMAL: number = 0;
readonly OPEN_TRIGGERED: number = 1;

readonly device;
protected isStateful;
readonly accessoryConfiguration: AccessoryConfiguration;

protected defaultState;
protected hasResetTimer;
protected hasCompanionSensor;

protected storagePath: string;

Expand All @@ -37,22 +35,22 @@ export abstract class VirtualAccessory {
this.accessory = accessory;
this.platform = platform;

// The device configuration is stored in the context in VirtualAccessoryPlatform.discoverDevices()
this.device = accessory.context.deviceConfiguration;

this.platform.log.debug(`[${this.device.accessoryName}] Accessory context: ${JSON.stringify(accessory.context)}`);
// The accessory configuration is stored in the context in VirtualAccessoryPlatform.discoverDevices()
this.accessoryConfiguration = accessory.context.deviceConfiguration;

this.isStateful = this.device.accessoryIsStateful;
this.hasResetTimer = this.device.accessoryHasResetTimer;
this.hasCompanionSensor = this.device.accessoryHasCompanionSensor;
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Accessory context: ${JSON.stringify(accessory.context)}`);

this.storagePath = accessory.context.storagePath;

if (!this.isStateful) {
if (!this.accessoryConfiguration.accessoryIsStateful) {
this.deleteState(this.storagePath);
}
}

/**
* Protected methods
*/

protected loadState(
storagePath: string,
key: string,
Expand All @@ -64,7 +62,7 @@ export abstract class VirtualAccessory {

const json = JSON.parse(contents);

this.platform.log.debug(`[${this.device.accessoryName}] Stored state: ${JSON.stringify(json)}`);
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Stored state: ${JSON.stringify(json)}`);
return json[key];
}

Expand All @@ -74,7 +72,7 @@ export abstract class VirtualAccessory {
value: boolean | number,
): void {
// Overwrite the existing persistence file
this.platform.log.debug(`[${this.device.accessoryName}] Saving state: ${key} ${value}`);
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Saving state: ${key} ${value}`);
fs.writeFileSync(
storagePath,
JSON.stringify({
Expand Down
18 changes: 8 additions & 10 deletions src/accessories/virtualAccessoryDoorbell.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import type { CharacteristicValue, PlatformAccessory } from 'homebridge';

import { VirtualAccessoryPlatform } from '../platform.js';
import { VirtualAccessory } from './virtualAccessory.js';
import { Accessory } from './virtualAccessory.js';

/**
* Platform Accessory
* An instance of this class is created for each accessory your platform registers
* Each accessory may expose multiple services of different service types.
* Doorbell - Accessory implementation
*/
export class VirtualDoorbellAccessory extends VirtualAccessory {
export class Doorbell extends Accessory {

private SINGLE_PRESS: number = this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS; // 0
private DOUBLE_PRESS: number = this.platform.Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS; // 1
Expand All @@ -29,7 +27,7 @@ export class VirtualDoorbellAccessory extends VirtualAccessory {
super(platform, accessory);

// First configure the device based on the accessory details
this.states.Volume = this.device.doorbellVolume;
this.states.Volume = this.accessoryConfiguration.doorbellVolume;

// set accessory information
this.accessory.getService(this.platform.Service.AccessoryInformation)!
Expand All @@ -43,7 +41,7 @@ export class VirtualDoorbellAccessory extends VirtualAccessory {

// set the service name, this is what is displayed as the default name on the Home app
// in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
this.service.setCharacteristic(this.platform.Characteristic.Name, this.device.accessoryName);
this.service.setCharacteristic(this.platform.Characteristic.Name, this.accessoryConfiguration.accessoryName);

// each service must implement at-minimum the "required characteristics" for the given service type
// see https://developers.homebridge.io/#/service/Lightbulb
Expand Down Expand Up @@ -78,7 +76,7 @@ export class VirtualDoorbellAccessory extends VirtualAccessory {
// implement your own code to check if the device is on
const pressEvent = this.SINGLE_PRESS;

this.platform.log.debug(`[${this.device.accessoryName}] Getting Programmable Switch Event: ${this.getEventName(pressEvent)}`);
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Programmable Switch Event: ${this.getEventName(pressEvent)}`);

// if you need to return an error to show the device as "Not Responding" in the Home app:
// throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
Expand All @@ -92,7 +90,7 @@ export class VirtualDoorbellAccessory extends VirtualAccessory {
// implement your own code to turn your device on/off
this.states.Volume = value as number;

this.platform.log.info(`[${this.device.accessoryName}] Setting Volume to ${this.states.Volume}`);
this.platform.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Volume to ${this.states.Volume}`);
}

/**
Expand All @@ -112,7 +110,7 @@ export class VirtualDoorbellAccessory extends VirtualAccessory {
// implement your own code to check if the device is on
const volume = this.states.Volume;

this.platform.log.debug(`[${this.device.accessoryName}] Getting Volume: ${volume}`);
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Volume: ${volume}`);

// if you need to return an error to show the device as "Not Responding" in the Home app:
// throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
Expand Down
27 changes: 13 additions & 14 deletions src/accessories/virtualAccessoryGarageDoor.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import type { CharacteristicValue, PlatformAccessory } from 'homebridge';

import { VirtualAccessoryPlatform } from '../platform.js';
import { VirtualAccessory } from './virtualAccessory.js';
import { Accessory } from './virtualAccessory.js';

/**
* Platform Accessory
* An instance of this class is created for each accessory your platform registers
* Each accessory may expose multiple services of different service types.
* GarageDoor - Accessory implementation
*/
export class VirtualGarageDoorAccessory extends VirtualAccessory {
export class GarageDoor extends Accessory {

private OPEN: number = this.platform.Characteristic.CurrentDoorState.OPEN; // 0
private CLOSED: number = this.platform.Characteristic.CurrentDoorState.CLOSED; // 1
Expand All @@ -34,10 +32,10 @@ export class VirtualGarageDoorAccessory extends VirtualAccessory {
super(platform, accessory);

// First configure the device based on the accessory details
this.defaultState = this.device.garageDoorDefaultState === 'open' ? this.OPEN : this.CLOSED;
this.defaultState = this.accessoryConfiguration.garageDoorDefaultState === 'open' ? this.OPEN : this.CLOSED;

// If the accessory is stateful retrieve stored state, otherwise set to default state
if (this.isStateful) {
if (this.accessoryConfiguration.accessoryIsStateful) {
const cachedState = this.loadState(this.storagePath, this.stateStorageKey) as number;

if (cachedState !== undefined) {
Expand All @@ -61,10 +59,11 @@ export class VirtualGarageDoorAccessory extends VirtualAccessory {

// set the service name, this is what is displayed as the default name on the Home app
// in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
this.service.setCharacteristic(this.platform.Characteristic.Name, this.device.accessoryName);
this.service.setCharacteristic(this.platform.Characteristic.Name, this.accessoryConfiguration.accessoryName);

// Update the initial state of the accessory
this.platform.log.debug(`[${this.device.accessoryName}] Setting Garage Door Current State: ${this.getStateName(this.states.GarageDoorState)}`);
// eslint-disable-next-line max-len
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Setting Garage Door Current State: ${this.getStateName(this.states.GarageDoorState)}`);
this.service.updateCharacteristic(this.platform.Characteristic.CurrentDoorState, (this.states.GarageDoorState));
this.service.updateCharacteristic(this.platform.Characteristic.TargetDoorState, (this.states.GarageDoorState));

Expand Down Expand Up @@ -104,7 +103,7 @@ export class VirtualGarageDoorAccessory extends VirtualAccessory {
// implement your own code to check if the device is on
const garageDoorState = this.states.GarageDoorState;

this.platform.log.debug(`[${this.device.accessoryName}] Getting Current Door State: ${this.getStateName(garageDoorState)}`);
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Current Door State: ${this.getStateName(garageDoorState)}`);

// if you need to return an error to show the device as "Not Responding" in the Home app:
// throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
Expand All @@ -121,11 +120,11 @@ export class VirtualGarageDoorAccessory extends VirtualAccessory {
this.states.GarageDoorState = value as number;

// Store device state if stateful
if (this.isStateful) {
if (this.accessoryConfiguration.accessoryIsStateful) {
this.saveState(this.storagePath, this.stateStorageKey, this.states.GarageDoorState);
}

this.platform.log.info(`[${this.device.accessoryName}] Setting Target Door State: ${this.getStateName(this.states.GarageDoorState)}`);
this.platform.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Target Door State: ${this.getStateName(this.states.GarageDoorState)}`);
}

/**
Expand All @@ -145,7 +144,7 @@ export class VirtualGarageDoorAccessory extends VirtualAccessory {
// implement your own code to check if the device is on
const garageDoorState = this.states.GarageDoorState;

this.platform.log.debug(`[${this.device.accessoryName}] Getting Target Door State: ${this.getStateName(garageDoorState)}`);
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Target Door State: ${this.getStateName(garageDoorState)}`);

// if you need to return an error to show the device as "Not Responding" in the Home app:
// throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
Expand All @@ -160,7 +159,7 @@ export class VirtualGarageDoorAccessory extends VirtualAccessory {
// implement your own code to check if the device is on
const obstructionDetected = this.states.ObstructionDetected;

this.platform.log.debug(`[${this.device.accessoryName}] Getting Obstruction Detected: ${obstructionDetected}`);
this.platform.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Obstruction Detected: ${obstructionDetected}`);

// if you need to return an error to show the device as "Not Responding" in the Home app:
// throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
Expand Down
Loading

0 comments on commit c530811

Please sign in to comment.