Skip to content

Commit

Permalink
Merge pull request #17 from RobinBol/fix/disable-entity-state-parsing
Browse files Browse the repository at this point in the history
Fix/disable entity state parsing
  • Loading branch information
RobinBol authored Feb 7, 2025
2 parents 98b2dee + 0c635ed commit f1603a3
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 154 deletions.
3 changes: 3 additions & 0 deletions .homeychangelog.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@
},
"1.1.3": {
"en": "Fixes an issue that could cause the app to crash in rare circumstances."
},
"1.1.4": {
"en": "Made parsing events from EP less CPU intensive."
}
}
2 changes: 1 addition & 1 deletion .homeycompose/app.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "io.everythingsmart",
"version": "1.1.3",
"version": "1.1.4",
"compatibility": ">=5.0.0",
"sdk": 3,
"platforms": ["local"],
Expand Down
40 changes: 10 additions & 30 deletions app.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
{
"_comment": "This file is generated. Please edit .homeycompose/app.json instead.",
"id": "io.everythingsmart",
"version": "1.1.3",
"version": "1.1.4",
"compatibility": ">=5.0.0",
"sdk": 3,
"platforms": [
"local"
],
"platforms": ["local"],
"name": {
"en": "Everything Smart"
},
"tags": {
"en": [
"everything",
"presence",
"everythingsmart",
"mmwave"
]
"en": ["everything", "presence", "everythingsmart", "mmwave"]
},
"brandColor": "#5621F5",
"description": {
"en": "Building a Better Smart Home"
},
"category": [
"security"
],
"category": ["security"],
"permissions": [],
"images": {
"small": "/assets/images/small.png",
Expand Down Expand Up @@ -56,16 +47,9 @@
"en": "Everything Presence Lite"
},
"class": "sensor",
"capabilities": [
"measure_luminance",
"alarm_motion"
],
"platforms": [
"local"
],
"connectivity": [
"lan"
],
"capabilities": ["measure_luminance", "alarm_motion"],
"platforms": ["local"],
"connectivity": ["lan"],
"discovery": "everything-presence-lite",
"images": {
"small": "/drivers/everything-presence-lite/assets/images/small.jpg",
Expand Down Expand Up @@ -297,12 +281,8 @@
}
}
},
"platforms": [
"local"
],
"connectivity": [
"lan"
],
"platforms": ["local"],
"connectivity": ["lan"],
"discovery": "everything-presence-one",
"images": {
"small": "/drivers/everything-presence-one/assets/images/small.jpg",
Expand Down Expand Up @@ -682,4 +662,4 @@
]
}
}
}
}
94 changes: 44 additions & 50 deletions drivers/everything-presence-lite/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,9 +430,13 @@ class EverythingPresenceLiteDevice extends Homey.Device {
}

// Subscribe to entity events
entity.on(`state`, (state: unknown) =>
this.onEntityState(parseEntityResult.data.config.objectId, state)
);
entity.on(`state`, (state: unknown) => {
try {
this.onEntityState(parseEntityResult.data.config.objectId, state);
} catch (err) {
this.debugEntity('Failed to handle entity state event', err);
}
});
}

/**
Expand All @@ -442,17 +446,8 @@ class EverythingPresenceLiteDevice extends Homey.Device {
* @param state
*/
onEntityState(entityId: string, state: unknown) {
const parseResult = entityStateSchema.safeParse(state);
if (!parseResult.success) {
this.debugEntity(
`Got invalid entity state for entityId ${entityId}, error:`,
parseResult.error,
state
);
return;
}

const parsedState = parseResult.data;
// Skip parsing which may cause CPU spikes
const parsedState = state as z.infer<typeof entityStateSchema>;

// Get entity
const entity = this.entities.get(entityId)?.data;
Expand All @@ -471,21 +466,21 @@ class EverythingPresenceLiteDevice extends Homey.Device {

switch (entity.config.deviceClass) {
case 'illuminance':
// Throw when state is not a number
z.number().parse(parsedState.state);
this.debugEntity(`Capability: measure_luminance: state event`, parsedState.state);
this.setCapabilityValue('measure_luminance', parsedState.state).catch((err) =>
this.debugEntity('Failed to set measure_luminance capability value', err)
);
if (typeof parsedState?.state === 'number') {
this.debugEntity(`Capability: measure_luminance: state event`, parsedState?.state);
this.setCapabilityValue('measure_luminance', parsedState?.state).catch((err) =>
this.debugEntity('Failed to set measure_luminance capability value', err)
);
}
break;
case 'occupancy':
// Throw when state is not a boolean
z.boolean().parse(parsedState.state);
if (includesBinarySensorOccupancy(entity)) {
this.debugEntity(`Capability: alarm_motion: state event`, parsedState.state);
this.setCapabilityValue('alarm_motion', parsedState.state).catch((err) =>
this.debugEntity('Failed to set alarm_motion capability value', err)
);
if (typeof parsedState?.state === 'boolean') {
if (includesBinarySensorOccupancy(entity)) {
this.debugEntity(`Capability: alarm_motion: state event`, parsedState?.state);
this.setCapabilityValue('alarm_motion', parsedState?.state).catch((err) =>
this.debugEntity('Failed to set alarm_motion capability value', err)
);
}
}
break;
default:
Expand All @@ -495,31 +490,30 @@ class EverythingPresenceLiteDevice extends Homey.Device {
// Read and update settings
switch (entity.config.objectId) {
case DRIVER_SETTINGS.MMWAVE_DISTANCE:
// Throw when state is not a number
z.number().parse(parsedState.state);
this.debugEntity(`Setting: ${entity.config.objectId}: state event`, parsedState.state);
this.setSettings({
[entity.config.objectId]: parsedState.state
}).catch((err) =>
this.debugEntity(
`Failed to set setting ${entity.config.objectId} to value: ${parsedState.state}, reason:`,
err
)
);
if (typeof parsedState?.state === 'number') {
this.debugEntity(`Setting: ${entity.config.objectId}: state event`, parsedState?.state);
this.setSettings({
[entity.config.objectId]: parsedState?.state
}).catch((err) =>
this.debugEntity(
`Failed to set setting ${entity.config.objectId} to value: ${parsedState?.state}, reason:`,
err
)
);
}
break;
case DRIVER_SETTINGS.ESP_32_LED:
// Throw when state is not a boolean
z.boolean().parse(parsedState.state);
this.debugEntity(`Setting: ${entity.config.objectId}: state event`, parsedState.state);
this.setSettings({
[entity.config.objectId]: parsedState.state
}).catch((err) =>
this.debugEntity(
`Failed to set setting ${entity.config.objectId} to value: ${parsedState.state}, reason:`,
err
)
);

if (typeof parsedState?.state === 'boolean') {
this.debugEntity(`Setting: ${entity.config.objectId}: state event`, parsedState?.state);
this.setSettings({
[entity.config.objectId]: parsedState?.state
}).catch((err) =>
this.debugEntity(
`Failed to set setting ${entity.config.objectId} to value: ${parsedState?.state}, reason:`,
err
)
);
}
break;
default:
this.debugEntity('Unknown setting:', entity.config.objectId);
Expand Down
140 changes: 67 additions & 73 deletions drivers/everything-presence-one/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,13 @@ class EverythingPresenceOneDevice extends Homey.Device {
}

// Subscribe to entity events
entity.on(`state`, (state: unknown) =>
this.onEntityState(parseEntityResult.data.config.objectId, state)
);
entity.on(`state`, (state: unknown) => {
try {
this.onEntityState(parseEntityResult.data.config.objectId, state);
} catch (err) {
this.debugEntity('Failed to handle entity state event', err);
}
});
}

/**
Expand All @@ -452,17 +456,8 @@ class EverythingPresenceOneDevice extends Homey.Device {
* @param state
*/
onEntityState(entityId: string, state: unknown) {
const parseResult = entityStateSchema.safeParse(state);
if (!parseResult.success) {
this.debugEntity(
`Got invalid entity state for entityId ${entityId}, error:`,
parseResult.error,
state
);
return;
}

const parsedState = parseResult.data;
// Skip parsing which may cause CPU spikes
const parsedState = state as z.infer<typeof entityStateSchema>;

// Get entity
const entity = this.entities.get(entityId)?.data;
Expand All @@ -479,50 +474,50 @@ class EverythingPresenceOneDevice extends Homey.Device {

switch (entity.config.deviceClass) {
case 'temperature':
// Throw when state is not a number
z.number().parse(parsedState.state);
this.debugEntity(`Capability: measure_temperature: state event`, parsedState.state);
this.setCapabilityValue('measure_temperature', parsedState.state).catch((err) =>
this.debugEntity('Failed to set measure_temperature capability value', err)
);
if (typeof parsedState?.state === 'number') {
this.debugEntity(`Capability: measure_temperature: state event`, parsedState?.state);
this.setCapabilityValue('measure_temperature', parsedState?.state).catch((err) =>
this.debugEntity('Failed to set measure_temperature capability value', err)
);
}
break;
case 'humidity':
// Throw when state is not a number
z.number().parse(parsedState.state);
this.debugEntity(`Capability: measure_humidity: state event`, parsedState.state);
this.setCapabilityValue('measure_humidity', parsedState.state).catch((err) =>
this.debugEntity('Failed to set measure_humidity capability value', err)
);
if (typeof parsedState?.state === 'number') {
this.debugEntity(`Capability: measure_humidity: state event`, parsedState?.state);
this.setCapabilityValue('measure_humidity', parsedState?.state).catch((err) =>
this.debugEntity('Failed to set measure_humidity capability value', err)
);
}
break;
case 'illuminance':
// Throw when state is not a number
z.number().parse(parsedState.state);
this.debugEntity(`Capability: measure_luminance: state event`, parsedState.state);
this.setCapabilityValue('measure_luminance', parsedState.state).catch((err) =>
this.debugEntity('Failed to set measure_luminance capability value', err)
);
if (typeof parsedState?.state === 'number') {
this.debugEntity(`Capability: measure_luminance: state event`, parsedState?.state);
this.setCapabilityValue('measure_luminance', parsedState?.state).catch((err) =>
this.debugEntity('Failed to set measure_luminance capability value', err)
);
}
break;
case 'motion':
// Throw when state is not a boolean
z.boolean().parse(parsedState.state);
this.debugEntity(`Capability: alarm_motion.pir: state event`, parsedState.state);
this.setCapabilityValue('alarm_motion.pir', parsedState.state).catch((err) =>
this.debugEntity('Failed to set alarm_motion.pir capability value', err)
);
if (typeof parsedState?.state === 'boolean') {
this.debugEntity(`Capability: alarm_motion.pir: state event`, parsedState?.state);
this.setCapabilityValue('alarm_motion.pir', parsedState?.state).catch((err) =>
this.debugEntity('Failed to set alarm_motion.pir capability value', err)
);
}
break;
case 'occupancy':
// Throw when state is not a boolean
z.boolean().parse(parsedState.state);
if (includesBinarySensorMMWave(entity)) {
this.debugEntity(`Capability: alarm_motion.mmwave: state event`, parsedState.state);
this.setCapabilityValue('alarm_motion.mmwave', parsedState.state).catch((err) =>
this.debugEntity('Failed to set alarm_motion.mmwave capability value', err)
);
} else if (includesBinarySensorOccupancy(entity)) {
this.debugEntity(`Capability: alarm_motion: state event`, parsedState.state);
this.setCapabilityValue('alarm_motion', parsedState.state).catch((err) =>
this.debugEntity('Failed to set alarm_motion capability value', err)
);
if (typeof parsedState?.state === 'boolean') {
if (includesBinarySensorMMWave(entity)) {
this.debugEntity(`Capability: alarm_motion.mmwave: state event`, parsedState?.state);
this.setCapabilityValue('alarm_motion.mmwave', parsedState?.state).catch((err) =>
this.debugEntity('Failed to set alarm_motion.mmwave capability value', err)
);
} else if (includesBinarySensorOccupancy(entity)) {
this.debugEntity(`Capability: alarm_motion: state event`, parsedState?.state);
this.setCapabilityValue('alarm_motion', parsedState?.state).catch((err) =>
this.debugEntity('Failed to set alarm_motion capability value', err)
);
}
}
break;
default:
Expand All @@ -535,32 +530,31 @@ class EverythingPresenceOneDevice extends Homey.Device {
case DRIVER_SETTINGS.MMWAVE_ON_LATENCY:
case DRIVER_SETTINGS.MMWAVE_OFF_LATENCY:
case DRIVER_SETTINGS.MMWAVE_DISTANCE:
// Throw when state is not a number
z.number().parse(parsedState.state);
this.debugEntity(`Setting: ${entity.config.objectId}: state event`, parsedState.state);
this.setSettings({
[entity.config.objectId]: parsedState.state
}).catch((err) =>
this.debugEntity(
`Failed to set setting ${entity.config.objectId} to value: ${parsedState.state}, reason:`,
err
)
);
if (typeof parsedState?.state === 'number') {
this.debugEntity(`Setting: ${entity.config.objectId}: state event`, parsedState?.state);
this.setSettings({
[entity.config.objectId]: parsedState?.state
}).catch((err) =>
this.debugEntity(
`Failed to set setting ${entity.config.objectId} to value: ${parsedState?.state}, reason:`,
err
)
);
}
break;
case DRIVER_SETTINGS.MMWAVE_LED:
case DRIVER_SETTINGS.ESP_32_STATUS_LED:
// Throw when state is not a boolean
z.boolean().parse(parsedState.state);
this.debugEntity(`Setting: ${entity.config.objectId}: state event`, parsedState.state);
this.setSettings({
[entity.config.objectId]: parsedState.state
}).catch((err) =>
this.debugEntity(
`Failed to set setting ${entity.config.objectId} to value: ${parsedState.state}, reason:`,
err
)
);

if (typeof parsedState?.state === 'boolean') {
this.debugEntity(`Setting: ${entity.config.objectId}: state event`, parsedState?.state);
this.setSettings({
[entity.config.objectId]: parsedState?.state
}).catch((err) =>
this.debugEntity(
`Failed to set setting ${entity.config.objectId} to value: ${parsedState?.state}, reason:`,
err
)
);
}
break;
default:
this.debugEntity('Unknown setting:', entity.config.objectId);
Expand Down

0 comments on commit f1603a3

Please sign in to comment.