From bf4b05f122fe9bdf2ce9b275c88251a269a6b110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Andr=C3=A9=20Roland?= Date: Sun, 17 Nov 2024 00:39:12 +0100 Subject: [PATCH 1/2] Expose moving as motion sensor --- src/converters/basic_sensors.ts | 2 ++ src/converters/basic_sensors/moving.ts | 30 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/converters/basic_sensors/moving.ts diff --git a/src/converters/basic_sensors.ts b/src/converters/basic_sensors.ts index cf171397..f83429a4 100644 --- a/src/converters/basic_sensors.ts +++ b/src/converters/basic_sensors.ts @@ -18,6 +18,7 @@ import { WaterLeakSensorHandler, GasLeakSensorHandler } from './basic_sensors/le import { CarbonMonoxideSensorHandler } from './basic_sensors/carbon_monoxide'; import { SmokeSensorHandler } from './basic_sensors/smoke'; import { VibrationSensorHandler } from './basic_sensors/vibration'; +import { MovingSensorHandler } from './basic_sensors/moving'; import { PresenceSensorHandler } from './basic_sensors/presence'; import { OccupancySensorHandler } from './basic_sensors/occupancy'; import { IdentifierGenerator } from './basic_sensors/basic'; @@ -52,6 +53,7 @@ export class BasicSensorCreator implements ServiceCreator { OccupancySensorHandler, PresenceSensorHandler, VibrationSensorHandler, + MovingSensorHandler, SmokeSensorHandler, CarbonMonoxideSensorHandler, WaterLeakSensorHandler, diff --git a/src/converters/basic_sensors/moving.ts b/src/converters/basic_sensors/moving.ts new file mode 100644 index 00000000..6c66d3a9 --- /dev/null +++ b/src/converters/basic_sensors/moving.ts @@ -0,0 +1,30 @@ +import { BasicAccessory } from '../interfaces'; +import { ExposesEntryWithBinaryProperty, ExposesEntryWithProperty } from '../../z2mModels'; +import { hap } from '../../hap'; +import { BinarySensorHandler } from './binary'; + +export class MovingSensorHandler extends BinarySensorHandler { + public static readonly exposesName: string = 'moving'; + + constructor(expose: ExposesEntryWithProperty, otherExposes: ExposesEntryWithBinaryProperty[], accessory: BasicAccessory) { + super( + accessory, + expose as ExposesEntryWithBinaryProperty, + otherExposes, + MovingSensorHandler.generateIdentifier, + 'Motion Sensor (moving)', + (n, t) => new hap.Service.MotionSensor(n, (MovingSensorHandler.exposesName + ' ' + (t ?? '')).trim()), + hap.Characteristic.MotionDetected, + true, + false + ); + } + + static generateIdentifier(endpoint: string | undefined) { + let identifier = MovingSensorHandler.exposesName + '_' + hap.Service.MotionSensor.UUID; + if (endpoint !== undefined) { + identifier += '_' + endpoint.trim(); + } + return identifier; + } +} From a117ab6b99357c1d90e80f203f9658962e104950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Andr=C3=A9=20Roland?= Date: Wed, 20 Nov 2024 21:59:39 +0100 Subject: [PATCH 2/2] Added documentation, test and created changelog entry --- .gitignore | 3 +- CHANGELOG.md | 4 ++ docs/sensors.md | 1 + test/basic_sensors.spec.ts | 44 ++++++++++++++++++++++ test/exposes/smartthings/im6001-mpp01.json | 36 ++++++++++++++++++ 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 test/exposes/smartthings/im6001-mpp01.json diff --git a/.gitignore b/.gitignore index e52bf75d..45212a99 100644 --- a/.gitignore +++ b/.gitignore @@ -138,4 +138,5 @@ inspectionProfiles/ # Other things reports/ _*.json -**/_*.ts \ No newline at end of file +**/_*.ts +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c7fc4a..e0aab16a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Since version 1.0.0, we try to follow the [Semantic Versioning](https://semver.o ## [Unreleased] +### Added + +- Expose moving as motion sensor. + ## [1.11.0-beta.6] - 2024-06-30 ### Changed diff --git a/docs/sensors.md b/docs/sensors.md index 4ab83c63..ea782a80 100644 --- a/docs/sensors.md +++ b/docs/sensors.md @@ -21,6 +21,7 @@ The following table shows the possible exposes entries and the services and char | `contact` | published | [Contact Sensor](https://developers.homebridge.io/#/service/ContactSensor) | [Contact Sensor State](https://developers.homebridge.io/#/characteristic/ContactSensorState) | | | `occupancy` | published | [Occupancy Sensor](https://developers.homebridge.io/#/service/OccupancySensor) | [Occupancy Detected](https://developers.homebridge.io/#/characteristic/OccupancyDetected) | | | `vibration` | published | [Motion Sensor](https://developers.homebridge.io/#/service/MotionSensor) | [Motion Detected](https://developers.homebridge.io/#/characteristic/MotionDetected) | | +| `moving` | published | [Motion Sensor](https://developers.homebridge.io/#/service/MotionSensor) | [Motion Detected](https://developers.homebridge.io/#/characteristic/MotionDetected) | | | `smoke` | published | [Smoke Sensor](https://developers.homebridge.io/#/service/SmokeSensor) | [Smoke Detected](https://developers.homebridge.io/#/characteristic/SmokeDetected) | | | `carbon_monoxide` | published | [Carbon Monoxide Sensor](https://developers.homebridge.io/#/service/CarbonMonoxideSensor) | [Carbon Monoxide Detected](https://developers.homebridge.io/#/characteristic/CarbonMonoxideDetected) | | | `co2` | published | [Carbon Dioxide Sensor](https://developers.homebridge.io/#/service/CarbonDioxideSensor) | [Carbon Dioxide Detected](https://developers.homebridge.io/#/characteristic/CarbonDioxideDetected) / [Carbon Dioxide Level](https://developers.homebridge.io/#/characteristic/CarbonDioxideLevel) | Detection threshold is currently fixed at 1200 ppm | diff --git a/test/basic_sensors.spec.ts b/test/basic_sensors.spec.ts index 403edbf9..88983cfd 100644 --- a/test/basic_sensors.spec.ts +++ b/test/basic_sensors.spec.ts @@ -645,4 +645,48 @@ describe('Basic Sensors', () => { ); }); }); + + describe('SmartThings IM6001-MPP01', () => { + // Shared "state" + let deviceExposes: ExposesEntry[] = []; + let harness: ServiceHandlersTestHarness; + let movingSensorId: string; + + beforeEach(() => { + // Only test service creation for first test case and reuse harness afterwards + if (deviceExposes.length === 0 && harness === undefined) { + // Load exposes from JSON + deviceExposes = loadExposesFromFile('smartthings/im6001-mpp01.json'); + expect(deviceExposes.length).toBeGreaterThan(0); + const newHarness = new ServiceHandlersTestHarness(); + + // Check service creation + movingSensorId = 'moving_' + hap.Service.MotionSensor.UUID; + newHarness + .getOrAddHandler(hap.Service.MotionSensor, 'moving', movingSensorId) + .addExpectedCharacteristic('moving', hap.Characteristic.MotionDetected); + newHarness.prepareCreationMocks(); + + newHarness.callCreators(deviceExposes); + + newHarness.checkCreationExpectations(); + newHarness.checkHasMainCharacteristics(); + newHarness.checkExpectedGetableKeys([]); + harness = newHarness; + } + harness?.clearMocks(); + }); + + afterEach(() => { + verifyAllWhenMocksCalled(); + resetAllWhenMocks(); + }); + + test('Update moving', (): void => { + expect(harness).toBeDefined(); + harness.checkSingleUpdateState('{"moving":false}', movingSensorId, hap.Characteristic.MotionDetected, false); + harness.clearMocks(); + harness.checkSingleUpdateState('{"moving":true}', movingSensorId, hap.Characteristic.MotionDetected, true); + }); + }); }); diff --git a/test/exposes/smartthings/im6001-mpp01.json b/test/exposes/smartthings/im6001-mpp01.json new file mode 100644 index 00000000..1d28736f --- /dev/null +++ b/test/exposes/smartthings/im6001-mpp01.json @@ -0,0 +1,36 @@ +[ + { + "name": "battery", + "label": "Battery", + "access": 1, + "type": "numeric", + "property": "battery", + "description": "Remaining battery in %, can take up to 24 hours before reported", + "category": "diagnostic", + "unit": "%", + "value_max": 100, + "value_min": 0 + }, + { + "name": "moving", + "label": "Moving", + "access": 1, + "type": "binary", + "property": "moving", + "description": "Indicates whether the device is moving", + "value_on": true, + "value_off": false + }, + { + "name": "linkquality", + "label": "Linkquality", + "access": 1, + "type": "numeric", + "property": "linkquality", + "description": "Link quality (signal strength)", + "category": "diagnostic", + "unit": "lqi", + "value_max": 255, + "value_min": 0 + } +]