Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add siren neo nas-ab02b2 #2034

Merged
6 changes: 5 additions & 1 deletion front/src/components/boxs/device-in-room/DeviceRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import NumberDeviceFeature from './device-features/NumberDeviceFeature';
import CoverDeviceFeature from './device-features/CoverDeviceFeature';
import ThermostatDeviceFeature from './device-features/ThermostatDeviceFeature';
import AirConditioningModeDeviceFeature from './device-features/AirConditioningModeDeviceFeature';
import LMHVolumeDeviceFeature from './device-features/LMHVolumeDeviceFeature';

const ROW_TYPE_BY_FEATURE_TYPE = {
[DEVICE_FEATURE_TYPES.LIGHT.BINARY]: BinaryDeviceFeature,
Expand All @@ -27,7 +28,10 @@ const ROW_TYPE_BY_FEATURE_TYPE = {
[DEVICE_FEATURE_TYPES.CURTAIN.POSITION]: MultiLevelDeviceFeature,
[DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE]: ThermostatDeviceFeature,
[DEVICE_FEATURE_TYPES.AIR_CONDITIONING.MODE]: AirConditioningModeDeviceFeature,
[DEVICE_FEATURE_TYPES.AIR_CONDITIONING.TARGET_TEMPERATURE]: ThermostatDeviceFeature
[DEVICE_FEATURE_TYPES.AIR_CONDITIONING.TARGET_TEMPERATURE]: ThermostatDeviceFeature,
[DEVICE_FEATURE_TYPES.SIREN.LMH_VOLUME]: LMHVolumeDeviceFeature,
[DEVICE_FEATURE_TYPES.SIREN.MELODY]: NumberDeviceFeature,
[DEVICE_FEATURE_TYPES.DURATION.DECIMAL]: MultiLevelDeviceFeature
};

const DeviceRow = ({ children, ...props }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ const SUPPORTED_FEATURE_TYPES = [
DEVICE_FEATURE_TYPES.SHUTTER.STATE,
DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE,
DEVICE_FEATURE_TYPES.AIR_CONDITIONING.MODE,
DEVICE_FEATURE_TYPES.AIR_CONDITIONING.TARGET_TEMPERATURE
DEVICE_FEATURE_TYPES.AIR_CONDITIONING.TARGET_TEMPERATURE,
DEVICE_FEATURE_TYPES.SIREN.LMH_VOLUME,
DEVICE_FEATURE_TYPES.SIREN.MELODY,
DEVICE_FEATURE_TYPES.DURATION.DECIMAL
];

export default SUPPORTED_FEATURE_TYPES;
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import get from 'get-value';
import { Text } from 'preact-i18n';
import cx from 'classnames';

import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts';
import { SIREN_LMH_VOLUME } from '../../../../../../server/utils/constants';

const LMHVolumeDeviceFeature = ({ children, ...props }) => {
const { deviceFeature } = props;
const { category, type, last_value: lastValue } = deviceFeature;

function updateValue(value) {
props.updateValueWithDebounce(deviceFeature, value);
}

function low() {
updateValue(SIREN_LMH_VOLUME.LOW);
}

function medium() {
updateValue(SIREN_LMH_VOLUME.MEDIUM);
}

function high() {
updateValue(SIREN_LMH_VOLUME.HIGH);
}

return (
<tr>
<td>
<i class={`fe fe-${get(DeviceFeatureCategoriesIcon, `${category}.${type}`, { default: 'sliders' })}`} />
</td>
<td>{props.rowName}</td>

<td class="py-0">
<div class="d-flex justify-content-end">
<div class="btn-group" role="group">
<button
class={cx('btn btn-sm btn-secondary', {
active: lastValue === SIREN_LMH_VOLUME.LOW
})}
onClick={low}
>
<Text id={`deviceFeatureAction.category.${category}.${type}.low`} plural={SIREN_LMH_VOLUME.HIGH} />
</button>
<button
class={cx('btn btn-sm btn-secondary', {
active: lastValue === SIREN_LMH_VOLUME.MEDIUM
})}
onClick={medium}
>
<Text id={`deviceFeatureAction.category.${category}.${type}.medium`} plural={SIREN_LMH_VOLUME.HIGH} />
</button>
<button
class={cx('btn btn-sm', 'btn-secondary', {
active: lastValue === SIREN_LMH_VOLUME.HIGH
})}
onClick={high}
>
<Text id={`deviceFeatureAction.category.${category}.${type}.high`} plural={SIREN_LMH_VOLUME.HIGH} />
</button>
</div>
</div>
</td>
</tr>
);
};

export default LMHVolumeDeviceFeature;
11 changes: 10 additions & 1 deletion front/src/config/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -2598,6 +2598,13 @@
"cooling": "Kühlen",
"heating": "Heizen"
}
},
"siren": {
"volume": {
"low": "Niedrig",
"medium": "Mittel",
"high": "Hoch"
}
}
}
},
Expand Down Expand Up @@ -2787,7 +2794,9 @@
},
"siren": {
"shortCategoryName": "Sirene",
"binary": "Sirene"
"binary": "Sirene",
"volume": "Lautstärke der Sirene",
"melody": "Melodie"
},
"cube": {
"shortCategoryName": "Würfel",
Expand Down
11 changes: 10 additions & 1 deletion front/src/config/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2600,6 +2600,13 @@
"cooling": "Cool",
"heating": "Heat"
}
},
"siren": {
"volume": {
"low": "Low",
"medium": "Medium",
"high": "High"
}
}
}
},
Expand Down Expand Up @@ -2789,7 +2796,9 @@
},
"siren": {
"shortCategoryName": "Siren",
"binary": "Siren"
"binary": "Siren",
"volume": "Siren volume",
"melody": "Melody"
},
"cube": {
"shortCategoryName": "Cube",
Expand Down
11 changes: 10 additions & 1 deletion front/src/config/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -2602,6 +2602,13 @@
"cooling": "Clim.",
"heating": "Chauffage"
}
},
"siren": {
"volume": {
"low": "Faible",
"medium": "Moyen",
"high": "Fort"
}
}
}
},
Expand Down Expand Up @@ -2791,7 +2798,9 @@
},
"siren": {
"shortCategoryName": "Sirène",
"binary": "Sirène On/Off"
"binary": "Sirène On/Off",
"volume": "Volume de la sirène",
"melody": "Mélodie"
},
"cube": {
"shortCategoryName": "Cube",
Expand Down
4 changes: 3 additions & 1 deletion front/src/utils/consts.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,9 @@ export const DeviceFeatureCategoriesIcon = {
[DEVICE_FEATURE_TYPES.SENSOR.INTEGER]: 'cloud'
},
[DEVICE_FEATURE_CATEGORIES.SIREN]: {
[DEVICE_FEATURE_TYPES.SIREN.BINARY]: 'bell'
[DEVICE_FEATURE_TYPES.SIREN.BINARY]: 'bell',
[DEVICE_FEATURE_TYPES.SIREN.LMH_VOLUME]: 'volume-1',
[DEVICE_FEATURE_TYPES.SIREN.MELODY]: 'music'
},
[DEVICE_FEATURE_CATEGORIES.TAMPER]: {
[DEVICE_FEATURE_TYPES.SENSOR.BINARY]: 'shield'
Expand Down
26 changes: 26 additions & 0 deletions server/services/zigbee2mqtt/exposes/enumType.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const {
DEVICE_FEATURE_TYPES,
BUTTON_STATUS,
COVER_STATE,
SIREN_LMH_VOLUME,
} = require('../../../utils/constants');

const WRITE_VALUE_MAPPING = {};
Expand Down Expand Up @@ -74,9 +75,17 @@ addMapping('state', COVER_STATE.OPEN, 'OPEN');
addMapping('state', COVER_STATE.CLOSE, 'CLOSE');
addMapping('state', COVER_STATE.STOP, 'STOP');

addMapping('volume', SIREN_LMH_VOLUME.LOW, 'low');
addMapping('volume', SIREN_LMH_VOLUME.MEDIUM, 'medium');
addMapping('volume', SIREN_LMH_VOLUME.HIGH, 'high');

module.exports = {
type: 'enum',
writeValue: (expose, value) => {
if (expose.name === 'melody') {
return value;
}

const relatedValue = (WRITE_VALUE_MAPPING[expose.name] || {})[value];

if (relatedValue && expose.values.includes(relatedValue)) {
Expand All @@ -86,6 +95,11 @@ module.exports = {
return undefined;
},
readValue: (expose, value) => {
if (expose.name === 'melody') {
const intValue = parseInt(value, 10);
return intValue;
}

const subValue = value.replace(/^(\d+_)?/, '');
return (READ_VALUE_MAPPING[expose.name] || {})[subValue];
},
Expand All @@ -111,6 +125,18 @@ module.exports = {
},
},
},
volume: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.SIREN,
type: DEVICE_FEATURE_TYPES.SIREN.LMH_VOLUME,
},
},
melody: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.SIREN,
type: DEVICE_FEATURE_TYPES.SIREN.MELODY,
},
},
},
getFeatureIndexes: (values = []) => {
const indexes = values
Expand Down
9 changes: 9 additions & 0 deletions server/services/zigbee2mqtt/exposes/numericType.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ module.exports = {
max: 100,
},
},
battpercentage: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.BATTERY,
type: DEVICE_FEATURE_TYPES.SENSOR.INTEGER,
unit: DEVICE_FEATURE_UNITS.PERCENT,
min: 0,
max: 100,
},
},
brightness: {
types: {
light: {
Expand Down
19 changes: 19 additions & 0 deletions server/test/services/zigbee2mqtt/exposes/melodyEnumType.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { assert } = require('chai');

const enumType = require('../../../../services/zigbee2mqtt/exposes/enumType');

describe('zigbee2mqtt melody enumType', () => {
const expose = {
name: 'melody',
};

it('should write value', () => {
const result = enumType.writeValue(expose, 1);
assert.equal(result, 1);
});

it(`should read value`, () => {
const result = enumType.readValue(expose, '1');
assert.equal(result, 1);
});
});
47 changes: 47 additions & 0 deletions server/test/services/zigbee2mqtt/exposes/volumeEnumType.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const { assert } = require('chai');

const enumType = require('../../../../services/zigbee2mqtt/exposes/enumType');
const { SIREN_LMH_VOLUME } = require('../../../../utils/constants');

describe('zigbee2mqtt volume enumType', () => {
const expose = {
name: 'volume',
values: ['low', 'medium', 'high'],
};

[
{ enumValue: 'low', intValue: SIREN_LMH_VOLUME.LOW },
{ enumValue: 'medium', intValue: SIREN_LMH_VOLUME.MEDIUM },
{ enumValue: 'high', intValue: SIREN_LMH_VOLUME.HIGH },
].forEach((mapping) => {
const { enumValue, intValue } = mapping;

it(`should write ${enumValue} value as ${intValue} value`, () => {
const result = enumType.writeValue(expose, intValue);
assert.equal(result, enumValue);
});

it(`should read ${intValue} value as ${enumValue}`, () => {
const result = enumType.readValue(expose, enumValue);
assert.equal(result, intValue);
});
});

it('should write undefined value on missing enum', () => {
const missingEnumExpose = {
values: ['low', 'medium'],
};
const result = enumType.writeValue(missingEnumExpose, SIREN_LMH_VOLUME.HIGH);
assert.equal(result, undefined);
});

it('should write undefined value', () => {
const result = enumType.writeValue(expose, 7);
assert.equal(result, undefined);
});

it('should read enum value', () => {
const result = enumType.readValue(expose, 'unknown');
assert.equal(result, undefined);
});
});
9 changes: 9 additions & 0 deletions server/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ const COVER_STATE = {
CLOSE: -1,
};

const SIREN_LMH_VOLUME = {
LOW: 0,
MEDIUM: 1,
HIGH: 2,
};

const AC_MODE = {
AUTO: 0,
COOLING: 1,
Expand Down Expand Up @@ -493,6 +499,8 @@ const DEVICE_FEATURE_TYPES = {
},
SIREN: {
BINARY: 'binary',
LMH_VOLUME: 'volume',
MELODY: 'melody',
},
CHILD_LOCK: {
BINARY: 'binary',
Expand Down Expand Up @@ -1106,6 +1114,7 @@ const ALARM_MODES_LIST = createList(ALARM_MODES);
module.exports.STATE = STATE;
module.exports.BUTTON_STATUS = BUTTON_STATUS;
module.exports.COVER_STATE = COVER_STATE;
module.exports.SIREN_LMH_VOLUME = SIREN_LMH_VOLUME;
module.exports.AC_MODE = AC_MODE;
module.exports.EVENTS = EVENTS;
module.exports.LIFE_EVENTS = LIFE_EVENTS;
Expand Down