Skip to content

Commit

Permalink
Object conversion algorithm in place
Browse files Browse the repository at this point in the history
  • Loading branch information
Zacknetic committed Aug 16, 2023
1 parent 2b221b7 commit 8f8b961
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 159 deletions.
8 changes: 4 additions & 4 deletions src/AccessoryGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep } from "magichome-platform";
import { IAccessoryContext, IAccessoryState, HomebridgeAccessory } from "./misc/types";
import { IAccessoryContext, IAccessoryState, HomebridgeAccessory } from "./misc/types/types";
import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from "homebridge";
import { HomebridgeMagichomeDynamicPlatform } from "./platform";

import { MHLogger } from "./MHLogger";
import { MHConfig } from "./MHConfig";
import { MHLogger } from "./misc/helpers/MHLogger";
import { MHConfig } from "./misc/helpers/MHConfig";

import { HomebridgeMagichomeDynamicPlatformAccessory } from "./platformAccessory";

Expand Down Expand Up @@ -71,7 +71,7 @@ export class AccessoryGenerator {
try {
setInterval(async () => {
MHLogger.trace("Scanning network for MagicHome accessories...");
console.log(this.offlineMHAccessories.keys());
MHLogger.trace("Offline devices: ", this.offlineMHAccessories.keys());
try {
const completeDevices: ICompleteDevice[] = await controllerGenerator.discoverCompleteDevices();
const baseControllers: Map<string, BaseController> = controllerGenerator.generateControllers(completeDevices);
Expand Down
139 changes: 0 additions & 139 deletions src/MHConfig.ts

This file was deleted.

58 changes: 58 additions & 0 deletions src/misc/helpers/MHConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { PlatformConfig } from "homebridge";
import { EXPECTED_CONFIG_STRUCTURE } from "../types/constants";
import { correctObjectShape } from "./utils";
interface AdvancedOptions {
periodicDiscovery: boolean;
namesWithMacAddress: boolean;
logLevel: number;
additionalSubnets: any[];
}

interface DeviceManagement {
blacklistOrWhitelist: string;
blacklistedUniqueIDs: any[];
}

interface WhiteEffects {
simultaniousDevicesColorWhite: boolean;
colorWhiteThreshold: number;
colorWhiteThresholdSimultaniousDevices: number;
colorOffThresholdSimultaniousDevices: number;
}

interface Pruning {
pruneMissingCachedAccessories: boolean;
restartsBeforeMissingAccessoriesPruned: number;
pruneAllAccessoriesNextRestart: boolean;
}

export interface CorrectedMHConfig {
pruning: Pruning;
whiteEffects: WhiteEffects;
deviceManagement: DeviceManagement;
advancedOptions: AdvancedOptions;
}

export class MHConfig {
private static instance: MHConfig;

public static pruning: Pruning;
public static whiteEffects: WhiteEffects;
public static deviceManagement: DeviceManagement;
public static advancedOptions: AdvancedOptions;

constructor(private hbConfig: PlatformConfig) {
if (MHConfig.instance) {
return;
}

const correctedConfig = correctObjectShape(hbConfig, EXPECTED_CONFIG_STRUCTURE) as CorrectedMHConfig;

MHConfig.pruning = correctedConfig.pruning;
MHConfig.whiteEffects = correctedConfig.whiteEffects;
MHConfig.deviceManagement = correctedConfig.deviceManagement;
MHConfig.advancedOptions = correctedConfig.advancedOptions;

MHConfig.instance = this;
}
}
File renamed without changes.
118 changes: 117 additions & 1 deletion src/misc/utils.ts → src/misc/helpers/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { existsSync, readFileSync } from 'fs';
import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform';
import { IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB } from './types';
import { IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB } from '../types/types';
import { MHLogger } from './MHLogger';


export function clamp(value: number, min: number, max: number) {
Expand Down Expand Up @@ -467,4 +468,119 @@ function convertMiredColorTemperatureToXY(temperature: number): [number, number]

function reverseGammaCorrection(v: number): number {
return (v <= 0.0031308) ? 12.92 * v : (1.0 + 0.055) * Math.pow(v, (1.0 / 2.4)) - 0.055;
}

export function correctObjectShape(targetObject: any, expectedKeys: any): any {
const correctedObject: any = {};

// Function to create a deep copy of an object
function deepCopy(obj: any): any {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const copy: any = Array.isArray(obj) ? [] : {};
for (const key in obj) {
copy[key] = deepCopy(obj[key]);
}
return copy;
}
// Initialize correctedObject with a deep copy of expectedKeys
for (const key in expectedKeys) {
correctedObject[key] = deepCopy(expectedKeys[key]);
}

function findAndCorrectKey(key: string, value: any, expectedObject: any, correctedObject: any) {
let closestKey: string | null = null;
let minDistance = Infinity;
let closestSection: string |string[]| null = null;

function searchKeys(obj: any, path: string[] = []) {
for (const k in obj) {
const newPath = [...path, k];
if (typeof obj[k] === 'object') {
searchKeys(obj[k], newPath);
} else {
const distance = levenshteinDistance(key, k);
if (distance < minDistance) {
minDistance = distance;
closestKey = k;
closestSection = newPath.slice(0, -1)
}
}
}
}

searchKeys(expectedObject);

if (minDistance < 5 && closestKey !== null && closestSection !== null) { // Threshold of 5, adjust as needed
let target = correctedObject;
for (const section of closestSection) {
target = target[section];
}
target[closestKey] = value;
} else {
console.warn(`Unexpected key: ${key}`);
// Handle the misplaced or misspelled key as needed
}
}


function correctSection(targetSection: any, expectedSection: any, correctedSection: any) {
if (!targetSection || !expectedSection) return; // Return if targetSection or expectedSection is null

for (const key in targetSection) {
if (expectedSection.hasOwnProperty(key)) {
if (expectedSection[key] === null) {
correctedSection[key] = targetSection[key]; // Use value from target object if expected value is null
} else if (typeof expectedSection[key] === 'object') {
correctedSection[key] = correctedSection[key] || {};
correctSection(targetSection[key], expectedSection[key], correctedSection[key]); // Recursively correct nested objects
} else {
correctedSection[key] = targetSection[key]; // Correct key, use value from target object
}
} else {
findAndCorrectKey(key, targetSection[key], expectedKeys, correctedObject); // Potentially misplaced key, find correct place
}
}

// Recursively search for misplaced keys in nested objects
for (const key in targetSection) {
if (typeof targetSection[key] === 'object') {
correctSection(targetSection[key], expectedSection, correctedSection);
}
}
}

correctSection(targetObject, expectedKeys, correctedObject);

return correctedObject;
}


function levenshteinDistance(a: string, b: string) {
const matrix = [];
let i, j;

if (a.length === 0) return b.length;
if (b.length === 0) return a.length;

for (i = 0; i <= b.length; i++) {
matrix[i] = [i];
}

for (j = 0; j <= a.length; j++) {
matrix[0][j] = j;
}

for (i = 1; i <= b.length; i++) {
for (j = 1; j <= a.length; j++) {
if (b.charAt(i - 1) === a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, Math.min(matrix[i][j - 1] + 1, matrix[i - 1][j] + 1));
}
}
}

return matrix[b.length][a.length];
}
Empty file removed src/misc/serviceCharacteristics.ts
Empty file.
23 changes: 20 additions & 3 deletions src/misc/constants.ts → src/misc/types/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*----------------------[DEFAULT VALIUES]----------------------*/
import type { CorrectedMHConfig } from "../MHConfig";
import type { IAccessoryCommand, IAccessoryState } from "./types";
import type { CorrectedMHConfig } from "../helpers/MHConfig";
import type { IAccessoryCommand, IAccessoryContext, IAccessoryState } from "./types";

export const COLOR_COMMAND_MODES = {
CCT: 'CCT',
Expand Down Expand Up @@ -58,4 +58,21 @@ export const EXPECTED_CONFIG_STRUCTURE: CorrectedMHConfig = {
logLevel: 3,
additionalSubnets: [],
},
};
};

export const EXPECTED_CONTEXT_STRUCTURE = {
displayName: 'Error',
deviceMetaData: {

controllerHardwareVersion: -1,
controllerFirmwareVersion: -1
},
assignedAnimations: null,
protoDevice: {
ipAddress: "",
uniqueId: "",
modelNumber: "",
},
latestUpdate: null,
isOnline: true,
}
File renamed without changes.
Loading

0 comments on commit 8f8b961

Please sign in to comment.