diff --git a/front/src/components/boxs/device-in-room/DeviceRow.jsx b/front/src/components/boxs/device-in-room/DeviceRow.jsx
index 1edd1f5f72..5f3f0dd3f6 100644
--- a/front/src/components/boxs/device-in-room/DeviceRow.jsx
+++ b/front/src/components/boxs/device-in-room/DeviceRow.jsx
@@ -14,6 +14,7 @@ import ThermostatDeviceFeature from './device-features/ThermostatDeviceFeature';
import AirConditioningModeDeviceFeature from './device-features/AirConditioningModeDeviceFeature';
import PilotWireModeDeviceFeature from './device-features/PilotWireModeDeviceFeature';
import LMHVolumeDeviceFeature from './device-features/LMHVolumeDeviceFeature';
+import PushDeviceFeature from './device-features/PushDeviceFeature';
const ROW_TYPE_BY_FEATURE_TYPE = {
[DEVICE_FEATURE_TYPES.LIGHT.BINARY]: BinaryDeviceFeature,
@@ -33,7 +34,8 @@ const ROW_TYPE_BY_FEATURE_TYPE = {
[DEVICE_FEATURE_TYPES.HEATER.PILOT_WIRE_MODE]: PilotWireModeDeviceFeature,
[DEVICE_FEATURE_TYPES.SIREN.LMH_VOLUME]: LMHVolumeDeviceFeature,
[DEVICE_FEATURE_TYPES.SIREN.MELODY]: NumberDeviceFeature,
- [DEVICE_FEATURE_TYPES.DURATION.DECIMAL]: MultiLevelDeviceFeature
+ [DEVICE_FEATURE_TYPES.DURATION.DECIMAL]: MultiLevelDeviceFeature,
+ [DEVICE_FEATURE_TYPES.BUTTON.PUSH]: PushDeviceFeature
};
const DeviceRow = ({ children, ...props }) => {
diff --git a/front/src/components/boxs/device-in-room/SupportedFeatureTypes.jsx b/front/src/components/boxs/device-in-room/SupportedFeatureTypes.jsx
index eeb2419339..5cb8f82ba4 100644
--- a/front/src/components/boxs/device-in-room/SupportedFeatureTypes.jsx
+++ b/front/src/components/boxs/device-in-room/SupportedFeatureTypes.jsx
@@ -16,7 +16,8 @@ const SUPPORTED_FEATURE_TYPES = [
DEVICE_FEATURE_TYPES.HEATER.PILOT_WIRE_MODE,
DEVICE_FEATURE_TYPES.SIREN.LMH_VOLUME,
DEVICE_FEATURE_TYPES.SIREN.MELODY,
- DEVICE_FEATURE_TYPES.DURATION.DECIMAL
+ DEVICE_FEATURE_TYPES.DURATION.DECIMAL,
+ DEVICE_FEATURE_TYPES.BUTTON.PUSH
];
export default SUPPORTED_FEATURE_TYPES;
diff --git a/front/src/components/boxs/device-in-room/device-features/PushDeviceFeature.jsx b/front/src/components/boxs/device-in-room/device-features/PushDeviceFeature.jsx
new file mode 100644
index 0000000000..30791fba6d
--- /dev/null
+++ b/front/src/components/boxs/device-in-room/device-features/PushDeviceFeature.jsx
@@ -0,0 +1,44 @@
+import { Component } from 'preact';
+import cx from 'classnames';
+import { Text } from 'preact-i18n';
+import style from './style.css';
+
+class PushDeviceComponent extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ loading: false
+ };
+ }
+ push = async () => {
+ await this.setState({ loading: true });
+ this.props.updateValue(this.props.deviceFeature, 1);
+ setTimeout(() => {
+ this.setState({ loading: false });
+ }, 350);
+ };
+
+ render(props, { loading }) {
+ return (
+
{
+ this.props.updateActionProperty(this.props.columnIndex, this.props.index, 'topic', e.target.value);
+ };
+ handleChangeMessage = text => {
+ const newMessage = text && text.length > 0 ? text : undefined;
+ this.props.updateActionProperty(this.props.columnIndex, this.props.index, 'message', newMessage);
+ };
+
+ render(props) {
+ return (
+
+ );
+ }
+}
+
+export default connect('httpClient', {})(SendZigbee2MqttMessage);
diff --git a/front/src/routes/scene/edit-scene/triggers/DeviceFeatureState.jsx b/front/src/routes/scene/edit-scene/triggers/DeviceFeatureState.jsx
index 2cac11f1c8..3e6474bdd1 100644
--- a/front/src/routes/scene/edit-scene/triggers/DeviceFeatureState.jsx
+++ b/front/src/routes/scene/edit-scene/triggers/DeviceFeatureState.jsx
@@ -1,5 +1,6 @@
import { Component } from 'preact';
import { connect } from 'unistore/preact';
+import { Text, Localizer } from 'preact-i18n';
import { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES } from '../../../../../../server/utils/constants';
@@ -24,6 +25,24 @@ class TurnOnLight extends Component {
}
};
+ onForDurationChange = e => {
+ e.preventDefault();
+ if (e.target.value) {
+ this.props.updateTriggerProperty(this.props.index, 'for_duration', Number(e.target.value) * 60 * 1000);
+ } else {
+ this.props.updateTriggerProperty(this.props.index, 'for_duration', '');
+ }
+ };
+
+ enableOrDisableForDuration = e => {
+ e.preventDefault();
+ if (e.target.checked) {
+ this.props.updateTriggerProperty(this.props.index, 'for_duration', 60 * 1000);
+ } else {
+ this.props.updateTriggerProperty(this.props.index, 'for_duration', undefined);
+ }
+ };
+
render(props, { selectedDeviceFeature }) {
let binaryDevice = false;
let presenceDevice = false;
@@ -55,12 +74,55 @@ class TurnOnLight extends Component {
{binaryDevice && }
- {presenceDevice && }
+ {presenceDevice && }
{buttonClickDevice && }
{pilotWireModeDevice && }
{defaultDevice && }
{thresholdDevice && }
+
+ {props.trigger.for_duration !== undefined && (
+
+ )}
);
}
diff --git a/front/src/routes/scene/edit-scene/triggers/device-states/PresenceSensorDeviceState.jsx b/front/src/routes/scene/edit-scene/triggers/device-states/PresenceSensorDeviceState.jsx
index e1a4d63307..8e086069f2 100644
--- a/front/src/routes/scene/edit-scene/triggers/device-states/PresenceSensorDeviceState.jsx
+++ b/front/src/routes/scene/edit-scene/triggers/device-states/PresenceSensorDeviceState.jsx
@@ -8,6 +8,18 @@ class PresenceSensorDeviceState extends Component {
this.props.updateTriggerProperty(this.props.index, 'threshold_only', false);
}
+ componentDidUpdate(prevProps) {
+ if (
+ prevProps.selectedDeviceFeature &&
+ this.props.selectedDeviceFeature &&
+ prevProps.selectedDeviceFeature.selector !== this.props.selectedDeviceFeature.selector
+ ) {
+ this.props.updateTriggerProperty(this.props.index, 'operator', '=');
+ this.props.updateTriggerProperty(this.props.index, 'value', 1);
+ this.props.updateTriggerProperty(this.props.index, 'threshold_only', false);
+ }
+ }
+
render() {
return (
diff --git a/front/src/utils/consts.js b/front/src/utils/consts.js
index 3df6aa1de0..aa0206e016 100644
--- a/front/src/utils/consts.js
+++ b/front/src/utils/consts.js
@@ -270,7 +270,8 @@ export const DeviceFeatureCategoriesIcon = {
[DEVICE_FEATURE_TYPES.CUBE.ROTATION]: 'rotate-cw'
},
[DEVICE_FEATURE_CATEGORIES.BUTTON]: {
- [DEVICE_FEATURE_TYPES.BUTTON.CLICK]: 'circle'
+ [DEVICE_FEATURE_TYPES.BUTTON.CLICK]: 'circle',
+ [DEVICE_FEATURE_TYPES.BUTTON.PUSH]: 'circle'
},
[DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR]: {
[DEVICE_FEATURE_TYPES.ENERGY_SENSOR.BINARY]: 'power',
@@ -280,6 +281,66 @@ export const DeviceFeatureCategoriesIcon = {
[DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE]: 'zap',
[DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX]: 'zap'
},
+ [DEVICE_FEATURE_CATEGORIES.TELEINFORMATION]: {
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.BINARY]: 'power',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EAST]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EAIT]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF01]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF02]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF03]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF04]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF05]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF06]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF07]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF08]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF09]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF10]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.PREF]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.PCOUP]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.VTIC]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.CCASN]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.CCASN_1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY2]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY3]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ2]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ3]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ4]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.IRMS1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.IRMS2]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.IRMS3]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS2]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS3]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD01]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD02]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD03]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD04]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.NTARF]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.CCAIN]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.CCAIN_1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTI]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXIN]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXIN_1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN2]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN3]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS2]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS3]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN_1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN2_1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN3_1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.HHPHC]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.ADPS]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX2]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX3]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.ADIR1]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.ADIR2]: 'zap',
+ [DEVICE_FEATURE_TYPES.TELEINFORMATION.ADIR3]: 'zap'
+ },
[DEVICE_FEATURE_CATEGORIES.SPEED_SENSOR]: {
[DEVICE_FEATURE_TYPES.SPEED_SENSOR.DECIMAL]: 'wind',
[DEVICE_FEATURE_TYPES.SPEED_SENSOR.INTEGER]: 'wind'
diff --git a/package-lock.json b/package-lock.json
index 3928d5c03b..222850ba32 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "gladys",
- "version": "4.48.0",
+ "version": "4.49.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "gladys",
- "version": "4.48.0",
+ "version": "4.49.0",
"hasInstallScript": true,
"license": "Apache-2.0",
"devDependencies": {
diff --git a/package.json b/package.json
index 0968fde836..2fa1348e02 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gladys",
- "version": "4.48.0",
+ "version": "4.49.0",
"description": "A privacy-first, open-source home assistant",
"main": "index.js",
"engines": {
diff --git a/server/lib/gateway/gateway.forwardMessageToOpenAI.js b/server/lib/gateway/gateway.forwardMessageToOpenAI.js
index bcdae2a0f9..29e84052c3 100644
--- a/server/lib/gateway/gateway.forwardMessageToOpenAI.js
+++ b/server/lib/gateway/gateway.forwardMessageToOpenAI.js
@@ -11,7 +11,7 @@ const intentTranslation = {
INFO: 'info.get-info',
};
-const disableOpenAiFirstReply = new Set(['GET_TEMPERATURE', 'GET_HUMIDITY']);
+const disableOpenAiFirstReply = new Set(['GET_TEMPERATURE', 'GET_HUMIDITY', 'NO_RESPONSE']);
/**
* @public
diff --git a/server/lib/scene/index.js b/server/lib/scene/index.js
index 1e1f26298d..eb141e567c 100644
--- a/server/lib/scene/index.js
+++ b/server/lib/scene/index.js
@@ -57,6 +57,7 @@ const SceneManager = function SceneManager(
this.sunCalc = sunCalc;
this.scheduler = scheduler;
this.jobs = [];
+ this.checkTriggersDurationTimer = new Map();
this.event.on(EVENTS.TRIGGERS.CHECK, eventFunctionWrapper(this.checkTrigger.bind(this)));
this.event.on(EVENTS.ACTION.TRIGGERED, eventFunctionWrapper(this.executeSingleAction.bind(this)));
// on timezone change, reload all scenes
diff --git a/server/lib/scene/scene.actions.js b/server/lib/scene/scene.actions.js
index dafbcc422e..99df9acc72 100644
--- a/server/lib/scene/scene.actions.js
+++ b/server/lib/scene/scene.actions.js
@@ -565,6 +565,14 @@ const actionsFunc = {
mqttService.device.publish(action.topic, messageWithVariables);
}
},
+ [ACTIONS.ZIGBEE2MQTT.SEND]: (self, action, scope) => {
+ const zigbee2mqttService = self.service.getService('zigbee2mqtt');
+
+ if (zigbee2mqttService) {
+ const messageWithVariables = Handlebars.compile(action.message)(scope);
+ zigbee2mqttService.device.publish(action.topic, messageWithVariables);
+ }
+ },
[ACTIONS.MUSIC.PLAY_NOTIFICATION]: async (self, action, scope) => {
// Get device
const device = self.stateManager.get('device', action.device);
diff --git a/server/lib/scene/scene.checkTrigger.js b/server/lib/scene/scene.checkTrigger.js
index 8143e760e8..3d93c25b49 100644
--- a/server/lib/scene/scene.checkTrigger.js
+++ b/server/lib/scene/scene.checkTrigger.js
@@ -30,7 +30,7 @@ function checkTrigger(event) {
if (event.type === trigger.type) {
logger.debug(`Trigger ${trigger.type} is matching with event`);
// then we check the condition is verified
- const conditionVerified = triggersFunc[event.type](event, trigger);
+ const conditionVerified = triggersFunc[event.type](this, sceneSelector, event, trigger);
logger.debug(`Trigger ${trigger.type}, conditionVerified = ${conditionVerified}...`);
// if yes, we execute the scene
diff --git a/server/lib/scene/scene.triggers.js b/server/lib/scene/scene.triggers.js
index 6761088484..a557459d61 100644
--- a/server/lib/scene/scene.triggers.js
+++ b/server/lib/scene/scene.triggers.js
@@ -1,38 +1,106 @@
+const cloneDeep = require('lodash.clonedeep');
+
+const logger = require('../../utils/logger');
const { EVENTS } = require('../../utils/constants');
const { compare } = require('../../utils/compare');
const triggersFunc = {
- [EVENTS.DEVICE.NEW_STATE]: (event, trigger) => {
- // we check that we are talking about the same event
+ [EVENTS.DEVICE.NEW_STATE]: (self, sceneSelector, event, trigger) => {
+ // we check that we are talking about the same device feature
if (event.device_feature !== trigger.device_feature) {
return false;
}
+
+ // We verify if both old value and new value validate the rule
const newValueValidateRule = compare(trigger.operator, event.last_value, trigger.value);
- // if the trigger is only a threshold_only, we only validate the trigger is the rule has been validated
- // and was not validated with the previous value
- if (trigger.threshold_only === true && !Number.isNaN(event.previous_value)) {
- const previousValueValidateRule = compare(trigger.operator, event.previous_value, trigger.value);
- return newValueValidateRule && !previousValueValidateRule;
+ const previousValueValidateRule = compare(trigger.operator, event.previous_value, trigger.value);
+
+ const triggerDurationKey = `device.new-state.${sceneSelector}.${trigger.device_feature}:${trigger.operator}:${trigger.value}`;
+
+ // If the previous value was validating the rule, and the new value is not
+ // We clear any timeout for this trigger
+ if (previousValueValidateRule && !newValueValidateRule && self.checkTriggersDurationTimer.get(triggerDurationKey)) {
+ logger.info(
+ `Cancelling timer on trigger for device_feature ${trigger.device_feature}, because condition is no longer valid`,
+ );
+ clearTimeout(self.checkTriggersDurationTimer.get(triggerDurationKey));
+ self.checkTriggersDurationTimer.delete(triggerDurationKey);
+ }
+
+ if (trigger.for_duration === undefined) {
+ // If the trigger is only a threshold_only, we only validate the trigger is the rule has been validated
+ // and was not validated with the previous value
+ if (trigger.threshold_only === true && !Number.isNaN(event.previous_value)) {
+ return newValueValidateRule && !previousValueValidateRule;
+ }
+
+ return newValueValidateRule;
}
- return newValueValidateRule;
+
+ // If the "for_duration_finished" is here, it means we are
+ // checking the state after the timeout
+ if (event.for_duration_finished && triggerDurationKey === event.trigger_duration_key) {
+ logger.info(`Scene trigger device.new-state: Timer for sensor ${trigger.device_feature} has finished.`);
+ clearTimeout(self.checkTriggersDurationTimer.get(triggerDurationKey));
+ self.checkTriggersDurationTimer.delete(triggerDurationKey);
+ return newValueValidateRule;
+ }
+
+ const isValidatedIfThresholdOnly =
+ trigger.threshold_only && !Number.isNaN(event.previous_value)
+ ? newValueValidateRule && !previousValueValidateRule
+ : true;
+
+ if (newValueValidateRule && isValidatedIfThresholdOnly) {
+ // If the timeout already exist, don't re-create it
+ const timeoutAlreadyExist = self.checkTriggersDurationTimer.get(triggerDurationKey);
+ if (timeoutAlreadyExist) {
+ logger.info(`Timer for "${trigger.device_feature}" already exist, not re-creating.`);
+ return false;
+ }
+ logger.info(
+ `Scheduling timer to check for device_feature "${trigger.device_feature}" state in ${trigger.for_duration}ms`,
+ );
+ // Create a timeout
+ const timeoutId = setTimeout(() => {
+ const lastValue = self.stateManager.get('deviceFeature', trigger.device_feature).last_value;
+ self.event.emit(EVENTS.TRIGGERS.CHECK, {
+ ...cloneDeep(event),
+ previous_value: event.last_value,
+ last_value: lastValue,
+ for_duration_finished: true,
+ trigger_duration_key: triggerDurationKey,
+ });
+ }, trigger.for_duration);
+ // Save the timeoutId in case we need to cancel it later
+ self.checkTriggersDurationTimer.set(triggerDurationKey, timeoutId);
+ // Return false, as we'll check this only in the future
+ return false;
+ }
+
+ return false;
},
- [EVENTS.TIME.CHANGED]: (event, trigger) => event.key === trigger.key,
- [EVENTS.TIME.SUNRISE]: (event, trigger) => event.house.selector === trigger.house,
- [EVENTS.TIME.SUNSET]: (event, trigger) => event.house.selector === trigger.house,
- [EVENTS.USER_PRESENCE.BACK_HOME]: (event, trigger) => event.house === trigger.house && event.user === trigger.user,
- [EVENTS.USER_PRESENCE.LEFT_HOME]: (event, trigger) => event.house === trigger.house && event.user === trigger.user,
- [EVENTS.HOUSE.EMPTY]: (event, trigger) => event.house === trigger.house,
- [EVENTS.HOUSE.NO_LONGER_EMPTY]: (event, trigger) => event.house === trigger.house,
- [EVENTS.AREA.USER_ENTERED]: (event, trigger) => event.user === trigger.user && event.area === trigger.area,
- [EVENTS.AREA.USER_LEFT]: (event, trigger) => event.user === trigger.user && event.area === trigger.area,
- [EVENTS.ALARM.ARM]: (event, trigger) => event.house === trigger.house,
- [EVENTS.ALARM.ARMING]: (event, trigger) => event.house === trigger.house,
- [EVENTS.ALARM.DISARM]: (event, trigger) => event.house === trigger.house,
- [EVENTS.ALARM.PARTIAL_ARM]: (event, trigger) => event.house === trigger.house,
- [EVENTS.ALARM.PANIC]: (event, trigger) => event.house === trigger.house,
- [EVENTS.ALARM.TOO_MANY_CODES_TESTS]: (event, trigger) => event.house === trigger.house,
+ [EVENTS.TIME.CHANGED]: (self, sceneSelector, event, trigger) => event.key === trigger.key,
+ [EVENTS.TIME.SUNRISE]: (self, sceneSelector, event, trigger) => event.house.selector === trigger.house,
+ [EVENTS.TIME.SUNSET]: (self, sceneSelector, event, trigger) => event.house.selector === trigger.house,
+ [EVENTS.USER_PRESENCE.BACK_HOME]: (self, sceneSelector, event, trigger) =>
+ event.house === trigger.house && event.user === trigger.user,
+ [EVENTS.USER_PRESENCE.LEFT_HOME]: (self, sceneSelector, event, trigger) =>
+ event.house === trigger.house && event.user === trigger.user,
+ [EVENTS.HOUSE.EMPTY]: (self, sceneSelector, event, trigger) => event.house === trigger.house,
+ [EVENTS.HOUSE.NO_LONGER_EMPTY]: (self, sceneSelector, event, trigger) => event.house === trigger.house,
+ [EVENTS.AREA.USER_ENTERED]: (self, sceneSelector, event, trigger) =>
+ event.user === trigger.user && event.area === trigger.area,
+ [EVENTS.AREA.USER_LEFT]: (self, sceneSelector, event, trigger) =>
+ event.user === trigger.user && event.area === trigger.area,
+ [EVENTS.ALARM.ARM]: (self, sceneSelector, event, trigger) => event.house === trigger.house,
+ [EVENTS.ALARM.ARMING]: (self, sceneSelector, event, trigger) => event.house === trigger.house,
+ [EVENTS.ALARM.DISARM]: (self, sceneSelector, event, trigger) => event.house === trigger.house,
+ [EVENTS.ALARM.PARTIAL_ARM]: (self, sceneSelector, event, trigger) => event.house === trigger.house,
+ [EVENTS.ALARM.PANIC]: (self, sceneSelector, event, trigger) => event.house === trigger.house,
+ [EVENTS.ALARM.TOO_MANY_CODES_TESTS]: (self, sceneSelector, event, trigger) => event.house === trigger.house,
[EVENTS.SYSTEM.START]: () => true,
- [EVENTS.MQTT.RECEIVED]: (event, trigger) =>
+ [EVENTS.MQTT.RECEIVED]: (self, sceneSelector, event, trigger) =>
event.topic === trigger.topic && (trigger.message === '' || trigger.message === event.message),
};
diff --git a/server/lib/session/session.get.js b/server/lib/session/session.get.js
index 90fe07e1eb..13307cbbba 100644
--- a/server/lib/session/session.get.js
+++ b/server/lib/session/session.get.js
@@ -37,6 +37,7 @@ async function get(userId, options) {
order: [[optionsWithDefault.order_by, optionsWithDefault.order_dir]],
where: {
revoked: false,
+ user_id: userId,
},
});
diff --git a/server/lib/user/user.get.js b/server/lib/user/user.get.js
index e99cb844d7..7e1aa0bcab 100644
--- a/server/lib/user/user.get.js
+++ b/server/lib/user/user.get.js
@@ -65,6 +65,8 @@ async function get(options) {
if (userPlain.picture && userPlain.picture.toString) {
userPlain.picture = userPlain.picture.toString('utf8');
}
+ delete userPlain.password;
+ delete userPlain.telegram_user_id;
return userPlain;
});
diff --git a/server/migrations/20241105200700-update-lixee-tic-features.js b/server/migrations/20241105200700-update-lixee-tic-features.js
new file mode 100644
index 0000000000..4b24fc077a
--- /dev/null
+++ b/server/migrations/20241105200700-update-lixee-tic-features.js
@@ -0,0 +1,895 @@
+const Promise = require('bluebird');
+const db = require('../models');
+const logger = require('../utils/logger');
+const { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES } = require('../utils/constants');
+
+module.exports = {
+ up: async (queryInterface, Sequelize) => {
+ // Get Zigbee2mqtt service
+ const service = await db.Service.findOne({
+ where: {
+ name: 'zigbee2mqtt',
+ },
+ });
+ if (service === null) {
+ logger.info('Zigbee2mqtt service not found.');
+ return;
+ }
+ logger.info(`Zigbee2mqtt migration: Found service zigbee2mqtt = ${service.id}`);
+ const zigbee2mqttDevices = await db.Device.findAll({
+ where: {
+ service_id: service.id,
+ },
+ });
+ logger.info(`Zigbee2mqtt migration: Found ${zigbee2mqttDevices.length} zigbee2mqtt devices`);
+
+ const lixeeTicdevices = await db.Device.findAll({
+ where: {
+ model: `ZLinky_TIC`,
+ },
+ });
+ logger.info(`Zigbee2mqtt migration: Found ${lixeeTicdevices.length} lixee-tic devices`);
+
+ await Promise.each(lixeeTicdevices, async (lixeeTicdevice) => {
+ // Load impacted features
+ const features = await db.DeviceFeature.findAll({
+ where: {
+ device_id: lixeeTicdevice.id,
+ },
+ });
+ logger.info(`Zigbee2mqtt migration: Found ${features.length} Linky_TIC features`);
+
+ await Promise.mapSeries(features, async (feature) => {
+ const { id, selector, name } = feature;
+
+ // Modify EAST
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EAST,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active délivrée totale (EAST)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EAIT
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-summ-received`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EAIT,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active injectée totale (EAIT)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF01
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier1-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF01,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF01)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF02
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier2-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF02,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF02)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF03
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier3-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF03,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF03)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF04
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier4-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF04,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF04)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF05
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier5-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF05,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF05)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF06
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier6-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF06,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF06)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF07
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier7-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF07,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF07)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF08
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier8-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF08,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF08)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF09
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier9-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF09,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF09)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASF10
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-tier10-summ-delivered`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF10,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée fournisseur (EASF10)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify PREF
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT}-available-power`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.PREF,
+ };
+
+ if (name === 'Intensité') {
+ currentFields.name = 'Puissance apparente référence (PREF)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify PCOUP
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT}-power-threshold`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.PCOUP,
+ };
+
+ if (name === 'Intensité') {
+ currentFields.name = 'Puissance apparente coupure (PCOUP)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify CCASN
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-active-power`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.CCASN,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = 'Position de la courbe charge active (CCASN)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify CCASN-1 Position de la courbe charge active (CCASN-1)
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-active-power-ph-b`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.CCASN_1,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = 'Position de la courbe charge active (CCASN-1)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify UMOY1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE}-average-rms-voltage-meas-period`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY1,
+ };
+
+ if (name === 'Tension') {
+ currentFields.name = 'Tension moyenne (UMOY1)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify UMOY2
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE}-average-rms-voltage-measure-period-ph-b`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY2,
+ };
+
+ if (name === 'Tension') {
+ currentFields.name = 'Tension moyenne (UMOY2)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify UMOY3
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE}-average-rms-voltage-meas-period-ph-c`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY3,
+ };
+
+ if (name === 'Tension') {
+ currentFields.name = 'Tension moyenne (UMOY3)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify ERQ1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-total-reactive-power`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ1,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = 'Puissance réactive Q1 totale (ERQ1)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify ERQ2
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-reactive-power`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ2,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = 'Puissance réactive Q2 totale (ERQ2)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify ERQ3
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-reactive-power-ph-b`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ3,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = 'Puissance réactive Q3 totale (ERQ3)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify ERQ4
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-reactive-power-ph-c`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ4,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = 'Puissance réactive Q4 totale (ERQ4)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify IRMS1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT}-rms-current`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IRMS1,
+ };
+
+ if (name === 'Intensité') {
+ currentFields.name = 'Courant efficace (IRMS1)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify URMS1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE}-rms-voltage`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS1,
+ };
+
+ if (name === 'Tension') {
+ currentFields.name = 'Tension efficace (URMS1)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify URMS2
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE}-rms-voltage-ph-b`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS2,
+ };
+
+ if (name === 'Tension') {
+ currentFields.name = 'Tension efficace (URMS2)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify URMS3
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE}-rms-voltage-ph-c`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS3,
+ };
+
+ if (name === 'Tension') {
+ currentFields.name = 'Tension efficace (URMS3)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASD01
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-active-energy-out-d01`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD01,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée distributeur (EASD01)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASD02
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-active-energy-out-d02`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD02,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée distributeur (EASD02)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASD03
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-active-energy-out-d03`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD03,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée distributeur (EASD03)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify EASD04
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-active-energy-out-d04`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD04,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = 'Energie active soutirée distributeur (EASD04)';
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify NTARF
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX}-current-index-tarif`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.NTARF,
+ };
+
+ if (name === 'Index') {
+ currentFields.name = `Numéro d'indice tarifaire (NTARF)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify CCAIN
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-injected-active-load-n`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.CCAIN,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Point n de la courbe de charge active retirée (CCAIN)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify CCAIN-1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-injected-active-load-n1`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.CCAIN_1,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Point n-1 de la courbe de charge active retirée (CCAIN-1)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SINSTI
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-injected-v-a`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTI,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente instantanée injectée (SINSTI)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SMAXIN
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-injected-v-a-max-n`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXIN,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente max. injectée n (SMAXIN)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SMAXIN-1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-injected-v-a-max-n1`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXIN_1,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente max. injectée n-1 (SMAXIN-1)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify RELAIS
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.BINARY}-relais`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.BINARY,
+ };
+
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SMAXN
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-active-power-max`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente max. soutirée (SMAXN)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SMAXN2
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-active-power-max-ph-b`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN2,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente max. soutirée (SMAXN2)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SMAXN3
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-active-power-max-ph-c`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN3,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente max. soutirée (SMAXN3)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SINSTS
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-apparent-power`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente instantanée soutirée (SINSTS)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SINSTS2
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-apparent-power-ph-b`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS2,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente instantanée soutirée (SINSTS2)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SINSTS3
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-apparent-power-ph-c`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS3,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente instantanée soutirée (SINSTS3)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SMAXN-1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-drawn-v-a-max-n1`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN_1,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente max. soutirée n-1 (SMAXN-1)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SMAXN2-1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-drawn-v-a-max-n1-p2`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN2_1,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente max. soutirée n-1 (SMAXN2-1)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify SMAXN3-1
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER}-drawn-v-a-max-n1-p3`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN3_1,
+ };
+
+ if (name === 'Puissance') {
+ currentFields.name = `Puissance apparente max. soutirée n-1 (SMAXN3-1)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify IMAX
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT}-rms-current-max`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX,
+ };
+
+ if (name === 'Intensité') {
+ currentFields.name = `Intensité maximale (IMAX)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify IMAX2
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT}-rms-current-max-ph-b`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX2,
+ };
+
+ if (name === 'Intensité') {
+ currentFields.name = `Intensité maximale (IMAX2)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+
+ // Modify IMAX3
+ if (
+ selector ===
+ `${service.selector}-${lixeeTicdevice.selector}-${DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR}-${DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT}-rms-current-max-ph-c`
+ ) {
+ const currentFields = {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX3,
+ };
+
+ if (name === 'Intensité') {
+ currentFields.name = `Intensité maximale (IMAX3)`;
+ }
+ await feature.update(currentFields);
+ logger.info(`Zigbee2mqtt migration: Updating device_feature ${id}`);
+ }
+ });
+ });
+ },
+ down: async (queryInterface, Sequelize) => {},
+};
diff --git a/server/models/scene.js b/server/models/scene.js
index 8143ab3097..7c91a90c7b 100644
--- a/server/models/scene.js
+++ b/server/models/scene.js
@@ -99,6 +99,7 @@ const triggersSchema = Joi.array().items(
time: Joi.string().regex(/^([0-9]{2}):([0-9]{2})$/),
interval: Joi.number(),
unit: Joi.string(),
+ for_duration: Joi.number(),
days_of_the_week: Joi.array().items(
Joi.string().valid('monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'),
),
diff --git a/server/services/zigbee2mqtt/exposes/enumType.js b/server/services/zigbee2mqtt/exposes/enumType.js
index 8193ad5bc0..d133356904 100644
--- a/server/services/zigbee2mqtt/exposes/enumType.js
+++ b/server/services/zigbee2mqtt/exposes/enumType.js
@@ -78,6 +78,15 @@ addMapping('action', BUTTON_STATUS.SHORT_RELEASE, 'short_release');
addMapping('action', BUTTON_STATUS.LONG_RELEASE, 'long_release');
addMapping('action', BUTTON_STATUS.DOUBLE_PRESS, 'double_press');
+addMapping('action', BUTTON_STATUS.TOGGLE, 'toggle');
+addMapping('action', BUTTON_STATUS.TOGGLE_HOLD, 'toggle_hold');
+addMapping('action', BUTTON_STATUS.BRIGHTNESS_UP_CLICK, 'brightness_up_click');
+addMapping('action', BUTTON_STATUS.BRIGHTNESS_UP_HOLD, 'brightness_up_hold');
+addMapping('action', BUTTON_STATUS.BRIGHTNESS_UP_RELEASE, 'brightness_up_release');
+addMapping('action', BUTTON_STATUS.BRIGHTNESS_DOWN_CLICK, 'brightness_down_click');
+addMapping('action', BUTTON_STATUS.BRIGHTNESS_DOWN_HOLD, 'brightness_down_hold');
+addMapping('action', BUTTON_STATUS.BRIGHTNESS_DOWN_RELEASE, 'brightness_down_release');
+
addMapping('state', COVER_STATE.OPEN, 'OPEN');
addMapping('state', COVER_STATE.CLOSE, 'CLOSE');
addMapping('state', COVER_STATE.STOP, 'STOP');
diff --git a/server/services/zigbee2mqtt/exposes/numericType.js b/server/services/zigbee2mqtt/exposes/numericType.js
index aa142a0ad2..d3498fa0cb 100644
--- a/server/services/zigbee2mqtt/exposes/numericType.js
+++ b/server/services/zigbee2mqtt/exposes/numericType.js
@@ -270,73 +270,73 @@ module.exports = {
},
},
// Lixee TIC Device
- BASE: {
+ EAST: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EAST,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- ISOUSC: {
+ EAIT: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EAIT,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- HCHC: {
+ EASF01: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF01,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- HCHP: {
+ EASF02: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF02,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- BBRHCJW: {
+ EASF03: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF03,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- BBRHPJW: {
+ EASF04: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF04,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- BBRHCJR: {
+ EASF05: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF05,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- BBRHPJR: {
+ EASF06: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF06,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
@@ -344,8 +344,8 @@ module.exports = {
},
EASF07: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF07,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
@@ -353,8 +353,8 @@ module.exports = {
},
EASF08: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF08,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
@@ -362,8 +362,8 @@ module.exports = {
},
EASF09: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF09,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
@@ -371,136 +371,142 @@ module.exports = {
},
EASF10: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASF10,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- IINST: {
+ PREF: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.PREF,
+ unit: DEVICE_FEATURE_UNITS.KILOVOLT_AMPERE,
},
},
- IINST2: {
+ PCOUP: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.PCOUP,
+ unit: DEVICE_FEATURE_UNITS.KILOVOLT_AMPERE,
},
},
- IINST3: {
+ VTIC: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.VTIC,
},
},
- IMAX: {
+ CCASN: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.CCASN,
+ unit: DEVICE_FEATURE_UNITS.WATT,
},
},
- IMAX2: {
+ 'CCASN-1': {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.CCASN_1,
+ unit: DEVICE_FEATURE_UNITS.WATT,
},
},
- IMAX3: {
+ UMOY1: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY1,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
},
},
- PMAX: {
+ UMOY2: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.WATT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY2,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
},
},
- SMAXN: {
+ UMOY3: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.UMOY2,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
},
},
- SMAXN2: {
+ ERQ1: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ1,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE_REACTIVE,
},
},
- SMAXN3: {
+ ERQ2: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ2,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE_REACTIVE,
},
},
- 'SMAXN-1': {
+ ERQ3: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ3,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE_REACTIVE,
},
},
- 'SMAXN2-1': {
+ ERQ4: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ERQ4,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE_REACTIVE,
},
},
- 'SMAXN3-1': {
+ IRMS1: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IRMS1,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
},
},
- PAPP: {
+ IRMS2: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IRMS2,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
},
},
- SINSTS: {
+ IRMS3: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IRMS3,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
},
},
- SINSTS2: {
+ URMS1: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS1,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
},
},
- SINSTS3: {
+ URMS2: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS2,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
+ },
+ },
+ URMS3: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.URMS3,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
},
},
EASD01: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD01,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
@@ -508,8 +514,8 @@ module.exports = {
},
EASD02: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD02,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
@@ -517,8 +523,8 @@ module.exports = {
},
EASD03: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD03,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
@@ -526,204 +532,285 @@ module.exports = {
},
EASD04: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.EASD04,
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- URMS1: {
+ NTARF: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE,
- unit: DEVICE_FEATURE_UNITS.VOLT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.NTARF,
},
},
- URMS2: {
+ CCAIN: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE,
- unit: DEVICE_FEATURE_UNITS.VOLT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.CCAIN,
+ unit: DEVICE_FEATURE_UNITS.WATT,
},
},
- URMS3: {
+ 'CCAIN-1': {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE,
- unit: DEVICE_FEATURE_UNITS.VOLT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.CCAIN_1,
+ unit: DEVICE_FEATURE_UNITS.WATT,
},
},
SINSTI: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTI,
unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
SMAXIN: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXIN,
unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
'SMAXIN-1': {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXIN_1,
unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- CCAIN: {
+ RELAIS: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.WATT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.BINARY,
},
},
- 'CCAIN-1': {
+ SMAXN: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.WATT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- CCASN: {
+ SMAXN2: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.WATT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN2,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- 'CCASN-1': {
+ SMAXN3: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.WATT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN3,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- UMOY1: {
+ SINSTS: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE,
- unit: DEVICE_FEATURE_UNITS.VOLT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- UMOY2: {
+ SINSTS2: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE,
- unit: DEVICE_FEATURE_UNITS.VOLT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS2,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- UMOY3: {
+ SINSTS3: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.VOLTAGE,
- unit: DEVICE_FEATURE_UNITS.VOLT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SINSTS3,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- ERQ2: {
+ 'SMAXN-1': {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE_REACTIVE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN_1,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- ERQ3: {
+ 'SMAXN2-1': {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE_REACTIVE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN2_1,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- ERQ4: {
+ 'SMAXN3-1': {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE_REACTIVE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.SMAXN3_1,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
},
},
- ERQ1: {
+ HHPHC: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
- unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE_REACTIVE,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.HHPHC,
},
},
- EAIT: {
+ IMAX: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
- unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
},
},
- NTARF: {
+ IMAX2: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX2,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
},
},
- IRMS1: {
+ IMAX3: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.IMAX3,
unit: DEVICE_FEATURE_UNITS.AMPERE,
},
},
- PREF: {
+ ADPS: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ADPS,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ },
+ },
+ ADIR1: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ADIR1,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ },
+ },
+ ADIR2: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ADIR2,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ },
+ },
+ ADIR3: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TELEINFORMATION,
+ type: DEVICE_FEATURE_TYPES.TELEINFORMATION.ADIR3,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ },
+ },
+ BASE: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.KILOVOLT_AMPERE,
+ type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
+ min: 0,
+ max: 1000000,
},
},
- PCOUP: {
+ ISOUSC: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
- unit: DEVICE_FEATURE_UNITS.KILOVOLT_AMPERE,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ min: 0,
+ max: 1000000,
},
},
- RELAIS: {
+ HCHC: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
- type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.BINARY,
+ type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
+ min: 0,
+ max: 1000000,
},
},
- EAST: {
+ HCHP: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- EASF01: {
+ BBRHCJW: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- EASF02: {
+ BBRHPJW: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
- EASF03: {
+ BBRHCJR: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
+ type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
+ min: 0,
+ max: 1000000,
+ },
+ },
+ BBRHPJR: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.INDEX,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
min: 0,
max: 1000000,
},
},
+ IINST: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
+ type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ },
+ },
+ IINST2: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
+ type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ },
+ },
+ IINST3: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
+ type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.CURRENT,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ },
+ },
+ PMAX: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
+ type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
+ unit: DEVICE_FEATURE_UNITS.WATT,
+ },
+ },
+ PAPP: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.ENERGY_SENSOR,
+ type: DEVICE_FEATURE_TYPES.ENERGY_SENSOR.POWER,
+ unit: DEVICE_FEATURE_UNITS.VOLT_AMPERE,
+ },
+ },
// End of Lixee TIC device
voc: {
feature: {
diff --git a/server/services/zigbee2mqtt/lib/index.js b/server/services/zigbee2mqtt/lib/index.js
index 058c3d79d3..15f70704d5 100644
--- a/server/services/zigbee2mqtt/lib/index.js
+++ b/server/services/zigbee2mqtt/lib/index.js
@@ -4,6 +4,7 @@ const { getConfiguration } = require('./getConfiguration');
const { saveConfiguration } = require('./saveConfiguration');
const { disconnect } = require('./disconnect');
const { handleMqttMessage } = require('./handleMqttMessage');
+const { publish } = require('./publish');
const { getDiscoveredDevices } = require('./getDiscoveredDevices');
const { findMatchingExpose } = require('./findMatchingExpose');
const { readValue } = require('./readValue');
@@ -70,6 +71,7 @@ Zigbee2mqttManager.prototype.getConfiguration = getConfiguration;
Zigbee2mqttManager.prototype.saveConfiguration = saveConfiguration;
Zigbee2mqttManager.prototype.disconnect = disconnect;
Zigbee2mqttManager.prototype.handleMqttMessage = handleMqttMessage;
+Zigbee2mqttManager.prototype.publish = publish;
Zigbee2mqttManager.prototype.getDiscoveredDevices = getDiscoveredDevices;
Zigbee2mqttManager.prototype.findMatchingExpose = findMatchingExpose;
Zigbee2mqttManager.prototype.readValue = readValue;
diff --git a/server/services/zigbee2mqtt/lib/publish.js b/server/services/zigbee2mqtt/lib/publish.js
new file mode 100644
index 0000000000..c7a4b58683
--- /dev/null
+++ b/server/services/zigbee2mqtt/lib/publish.js
@@ -0,0 +1,24 @@
+const logger = require('../../../utils/logger');
+const { ServiceNotConfiguredError } = require('../../../utils/coreErrors');
+
+/**
+ * @description Publish a MQTT message.
+ * @param {string} topic - MQTT Topic.
+ * @param {string} message - MQTT message.
+ * @example zigbee2mqtt.publish('zigbee2mqtt/test', '{}');
+ */
+function publish(topic, message) {
+ if (!this.mqttClient) {
+ throw new ServiceNotConfiguredError('MQTT is not configured.');
+ }
+ logger.debug(`Publishing MQTT message on topic ${topic}`);
+ this.mqttClient.publish(topic, message, undefined, (err) => {
+ if (err) {
+ logger.warn(`MQTT - Error publishing to ${topic} : ${err}`);
+ }
+ });
+}
+
+module.exports = {
+ publish,
+};
diff --git a/server/test/lib/gateway/gateway.forwardMessageToOpenAI.test.js b/server/test/lib/gateway/gateway.forwardMessageToOpenAI.test.js
index e6913af973..8eeca35d4e 100644
--- a/server/test/lib/gateway/gateway.forwardMessageToOpenAI.test.js
+++ b/server/test/lib/gateway/gateway.forwardMessageToOpenAI.test.js
@@ -205,6 +205,18 @@ describe('gateway.forwardMessageToOpenAI', () => {
intent: 'temperature-sensor.get-in-room',
});
});
+ it('should do nothing, no-response was sent', async () => {
+ gateway.gladysGatewayClient.openAIAsk = fake.resolves({
+ type: 'NO_RESPONSE',
+ answer: '',
+ room: '',
+ });
+ const classification = await gateway.forwardMessageToOpenAI({ message, previousQuestions, context });
+ expect(classification).to.deep.equal({
+ intent: undefined,
+ });
+ assert.notCalled(messageManager.reply);
+ });
it('should start scene from OpenAI', async () => {
gateway.gladysGatewayClient.openAIAsk = fake.resolves({
type: 'SCENE_START',
diff --git a/server/test/lib/scene/actions/scene.action.sendZigbee2MqttMessage.test.js b/server/test/lib/scene/actions/scene.action.sendZigbee2MqttMessage.test.js
new file mode 100644
index 0000000000..a9b710cf60
--- /dev/null
+++ b/server/test/lib/scene/actions/scene.action.sendZigbee2MqttMessage.test.js
@@ -0,0 +1,87 @@
+const { fake, assert } = require('sinon');
+const EventEmitter = require('events');
+
+const { ACTIONS } = require('../../../../utils/constants');
+const { executeActions } = require('../../../../lib/scene/scene.executeActions');
+
+const StateManager = require('../../../../lib/state');
+
+const event = new EventEmitter();
+
+describe('scene.send-zigbee2mqtt-message', () => {
+ it('should send message with value injected from device get-value', async () => {
+ const stateManager = new StateManager(event);
+ stateManager.setState('deviceFeature', 'my-device-feature', {
+ category: 'light',
+ type: 'binary',
+ last_value: 15,
+ });
+ const zigbee2MqttService = {
+ device: {
+ publish: fake.resolves(null),
+ },
+ };
+ const service = {
+ getService: fake.returns(zigbee2MqttService),
+ };
+ const scope = {};
+ await executeActions(
+ { stateManager, event, service },
+ [
+ [
+ {
+ type: ACTIONS.DEVICE.GET_VALUE,
+ device_feature: 'my-device-feature',
+ },
+ ],
+ [
+ {
+ type: ACTIONS.ZIGBEE2MQTT.SEND,
+ topic: '/my/mqtt/topic',
+ message: 'Temperature in the living room is {{0.0.last_value}} °C.',
+ },
+ ],
+ ],
+ scope,
+ );
+ assert.calledWith(zigbee2MqttService.device.publish, '/my/mqtt/topic', 'Temperature in the living room is 15 °C.');
+ });
+ it('should send message with value injected from http-request', async () => {
+ const stateManager = new StateManager(event);
+ const http = {
+ request: fake.resolves({ result: [15], error: null }),
+ };
+ const zigbee2MqttService = {
+ device: {
+ publish: fake.resolves(null),
+ },
+ };
+ const service = {
+ getService: fake.returns(zigbee2MqttService),
+ };
+ const scope = {};
+ await executeActions(
+ { stateManager, event, service, http },
+ [
+ [
+ {
+ type: ACTIONS.HTTP.REQUEST,
+ method: 'post',
+ url: 'http://test.test',
+ body: '{"toto":"toto"}',
+ headers: [],
+ },
+ ],
+ [
+ {
+ type: ACTIONS.ZIGBEE2MQTT.SEND,
+ topic: '/my/mqtt/topic',
+ message: 'Temperature in the living room is {{0.0.result.[0]}} °C.',
+ },
+ ],
+ ],
+ scope,
+ );
+ assert.calledWith(zigbee2MqttService.device.publish, '/my/mqtt/topic', 'Temperature in the living room is 15 °C.');
+ });
+});
diff --git a/server/test/lib/scene/scene.checkTrigger.test.js b/server/test/lib/scene/scene.checkTrigger.test.js
index 4ab3be0d81..7b43695395 100644
--- a/server/test/lib/scene/scene.checkTrigger.test.js
+++ b/server/test/lib/scene/scene.checkTrigger.test.js
@@ -57,80 +57,6 @@ describe('scene.checkTrigger', () => {
sinon.reset();
});
- it('should execute scene', async () => {
- sceneManager.addScene({
- selector: 'my-scene',
- active: true,
- actions: [
- [
- {
- type: ACTIONS.LIGHT.TURN_ON,
- devices: ['light-1'],
- },
- ],
- ],
- triggers: [
- {
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- value: 12,
- operator: '=',
- },
- ],
- });
- sceneManager.checkTrigger({
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- last_value: 12,
- });
- return new Promise((resolve, reject) => {
- sceneManager.queue.start(() => {
- try {
- assert.calledOnce(device.setValue);
- resolve();
- } catch (e) {
- reject(e);
- }
- });
- });
- });
- it('should not execute scene, scene not active', async () => {
- sceneManager.addScene({
- selector: 'my-scene',
- active: false,
- actions: [
- [
- {
- type: ACTIONS.LIGHT.TURN_ON,
- devices: ['light-1'],
- },
- ],
- ],
- triggers: [
- {
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- value: 12,
- operator: '=',
- },
- ],
- });
- sceneManager.checkTrigger({
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- last_value: 12,
- });
- return new Promise((resolve, reject) => {
- sceneManager.queue.start(() => {
- try {
- assert.notCalled(device.setValue);
- resolve();
- } catch (e) {
- reject(e);
- }
- });
- });
- });
it('should execute scene', async () => {
const addedScene = sceneManager.addScene({
selector: 'my-scene',
@@ -489,122 +415,6 @@ describe('scene.checkTrigger', () => {
});
});
});
-
- it('should not execute scene, condition not verified', async () => {
- sceneManager.addScene({
- selector: 'my-scene',
- active: true,
- actions: [
- [
- {
- type: ACTIONS.LIGHT.TURN_ON,
- devices: ['light-1'],
- },
- ],
- ],
- triggers: [
- {
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- value: 12,
- operator: '=',
- },
- ],
- });
- sceneManager.checkTrigger({
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- last_value: 14,
- });
- return new Promise((resolve, reject) => {
- sceneManager.queue.start(() => {
- try {
- assert.notCalled(device.setValue);
- resolve();
- } catch (e) {
- reject(e);
- }
- });
- });
- });
- it('should not execute scene, threshold already passed', async () => {
- sceneManager.addScene({
- selector: 'my-scene',
- active: true,
- actions: [
- [
- {
- type: ACTIONS.LIGHT.TURN_ON,
- devices: ['light-1'],
- },
- ],
- ],
- triggers: [
- {
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- value: 12,
- operator: '>',
- threshold_only: true,
- },
- ],
- });
- sceneManager.checkTrigger({
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- previous_value: 14,
- last_value: 14,
- });
- return new Promise((resolve, reject) => {
- sceneManager.queue.start(() => {
- try {
- assert.notCalled(device.setValue);
- resolve();
- } catch (e) {
- reject(e);
- }
- });
- });
- });
- it('should execute scene, threshold passed for the first time', async () => {
- sceneManager.addScene({
- selector: 'my-scene',
- active: true,
- actions: [
- [
- {
- type: ACTIONS.LIGHT.TURN_ON,
- devices: ['light-1'],
- },
- ],
- ],
- triggers: [
- {
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- value: 12,
- operator: '>',
- threshold_only: true,
- },
- ],
- });
- sceneManager.checkTrigger({
- type: EVENTS.DEVICE.NEW_STATE,
- device_feature: 'light-1',
- previous_value: 11,
- last_value: 14,
- });
- return new Promise((resolve, reject) => {
- sceneManager.queue.start(() => {
- try {
- assert.calledOnce(device.setValue);
- resolve();
- } catch (e) {
- reject(e);
- }
- });
- });
- });
it('should not execute scene, event not matching', async () => {
sceneManager.addScene({
selector: 'my-scene',
diff --git a/server/test/lib/scene/triggers/scene.trigger.alarmMode.test.js b/server/test/lib/scene/triggers/scene.trigger.alarmMode.test.js
index 283bdf61f7..e8db1371e4 100644
--- a/server/test/lib/scene/triggers/scene.trigger.alarmMode.test.js
+++ b/server/test/lib/scene/triggers/scene.trigger.alarmMode.test.js
@@ -215,6 +215,40 @@ describe('Scene.triggers.alarmMode', () => {
});
});
});
+ it('should execute scene with alarm.too-many-codes-tests trigger', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_OFF,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.ALARM.TOO_MANY_CODES_TESTS,
+ house: 'house-1',
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.ALARM.TOO_MANY_CODES_TESTS,
+ house: 'house-1',
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(() => {
+ try {
+ assert.calledOnce(device.setValue);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
it('should not execute scene (house not matching)', async () => {
sceneManager.addScene({
selector: 'my-scene',
diff --git a/server/test/lib/scene/triggers/scene.trigger.deviceNewState.test.js b/server/test/lib/scene/triggers/scene.trigger.deviceNewState.test.js
new file mode 100644
index 0000000000..374661573f
--- /dev/null
+++ b/server/test/lib/scene/triggers/scene.trigger.deviceNewState.test.js
@@ -0,0 +1,470 @@
+const sinon = require('sinon');
+const { expect } = require('chai');
+const EventEmitter = require('events');
+const Promise = require('bluebird');
+
+const { assert, fake } = sinon;
+
+const { EVENTS, ACTIONS } = require('../../../../utils/constants');
+const SceneManager = require('../../../../lib/scene');
+const StateManager = require('../../../../lib/state');
+
+const event = new EventEmitter();
+
+describe('scene.triggers.deviceNewState', () => {
+ let sceneManager;
+ let device;
+
+ const brain = {};
+
+ const service = {
+ getService: fake.returns({
+ device: {
+ subscribe: fake.returns(null),
+ },
+ }),
+ };
+
+ beforeEach(() => {
+ const house = {
+ get: fake.resolves([]),
+ };
+
+ device = {
+ setValue: fake.resolves(null),
+ };
+
+ const scheduler = {
+ scheduleJob: (date, callback) => {
+ return {
+ callback,
+ date,
+ cancel: () => {},
+ };
+ },
+ };
+
+ brain.addNamedEntity = fake.returns(null);
+ brain.removeNamedEntity = fake.returns(null);
+
+ const stateManager = new StateManager();
+ stateManager.setState('deviceFeature', 'light-1', {
+ last_value: 14,
+ });
+ sceneManager = new SceneManager(stateManager, event, device, {}, {}, house, {}, {}, {}, scheduler, brain, service);
+ });
+
+ afterEach(() => {
+ sinon.reset();
+ });
+
+ it('should execute scene', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '=',
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ last_value: 12,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(() => {
+ try {
+ assert.calledOnce(device.setValue);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should not execute scene, scene not active', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: false,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '=',
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ last_value: 12,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(() => {
+ try {
+ assert.notCalled(device.setValue);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should not execute scene, condition not verified', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '=',
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ last_value: 14,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(() => {
+ try {
+ assert.notCalled(device.setValue);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should not execute scene, device feature is not the same', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '=',
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-2',
+ last_value: 14,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(() => {
+ try {
+ assert.notCalled(device.setValue);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should not execute scene, threshold already passed', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '>',
+ threshold_only: true,
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ previous_value: 14,
+ last_value: 14,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(() => {
+ try {
+ assert.notCalled(device.setValue);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should execute scene, threshold passed for the first time', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '>',
+ threshold_only: true,
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ previous_value: 11,
+ last_value: 14,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(() => {
+ try {
+ assert.calledOnce(device.setValue);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should start timer to check later for state and not follow current scene', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '>',
+ threshold_only: true,
+ for_duration: 10 * 60 * 1000,
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ previous_value: 11,
+ last_value: 14,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(() => {
+ try {
+ assert.notCalled(device.setValue);
+ expect(sceneManager.checkTriggersDurationTimer.size).to.equal(1);
+ sceneManager.checkTriggersDurationTimer.forEach((value, timeoutKey) => {
+ expect(timeoutKey).to.equal('device.new-state.my-scene.light-1:>:12');
+ clearTimeout(value);
+ });
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should start timer to check now and condition should still be valid on second call', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '>',
+ threshold_only: true,
+ for_duration: 0, // now
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ previous_value: 11,
+ last_value: 14,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(async () => {
+ try {
+ await Promise.delay(5);
+ assert.calledOnce(device.setValue);
+ expect(sceneManager.checkTriggersDurationTimer.size).to.equal(0);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should start timer to check now and re-send new value still validating the condition', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '>',
+ threshold_only: false,
+ for_duration: 5,
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ previous_value: 11,
+ last_value: 14,
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ previous_value: 14,
+ last_value: 14,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(async () => {
+ try {
+ await Promise.delay(10);
+ assert.calledOnce(device.setValue);
+ expect(sceneManager.checkTriggersDurationTimer.size).to.equal(0);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+ it('should start timer to check now and condition should not be valid on second call', async () => {
+ sceneManager.addScene({
+ selector: 'my-scene',
+ active: true,
+ actions: [
+ [
+ {
+ type: ACTIONS.LIGHT.TURN_ON,
+ devices: ['light-1'],
+ },
+ ],
+ ],
+ triggers: [
+ {
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ value: 12,
+ operator: '>',
+ threshold_only: true,
+ for_duration: 10, // In 10ms
+ },
+ ],
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ previous_value: 11,
+ last_value: 14,
+ });
+ sceneManager.checkTrigger({
+ type: EVENTS.DEVICE.NEW_STATE,
+ device_feature: 'light-1',
+ previous_value: 14,
+ last_value: 5,
+ });
+ return new Promise((resolve, reject) => {
+ sceneManager.queue.start(async () => {
+ try {
+ await Promise.delay(5);
+ assert.notCalled(device.setValue);
+ expect(sceneManager.checkTriggersDurationTimer.size).to.equal(0);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ });
+});
diff --git a/server/test/security/user.test.js b/server/test/security/user.test.js
new file mode 100644
index 0000000000..3bb9aaa16b
--- /dev/null
+++ b/server/test/security/user.test.js
@@ -0,0 +1,16 @@
+const { expect } = require('chai');
+const { authenticatedRequest } = require('../controllers/request.test');
+
+describe('/api/v1/user/', () => {
+ it('should return all users without password', async () => {
+ await authenticatedRequest
+ .get('/api/v1/user?fields=password')
+ .expect('Content-Type', /json/)
+ .expect(200)
+ .then((res) => {
+ res.body.forEach((user) => {
+ expect(user).to.not.have.property('password');
+ });
+ });
+ });
+});
diff --git a/server/test/services/zigbee2mqtt/lib/publish.test.js b/server/test/services/zigbee2mqtt/lib/publish.test.js
new file mode 100644
index 0000000000..b658bcfe56
--- /dev/null
+++ b/server/test/services/zigbee2mqtt/lib/publish.test.js
@@ -0,0 +1,76 @@
+const sinon = require('sinon');
+const { expect } = require('chai');
+
+const { assert, fake } = sinon;
+
+const Zigbee2mqttManager = require('../../../../services/zigbee2mqtt/lib');
+const { ServiceNotConfiguredError } = require('../../../../utils/coreErrors');
+
+const serviceId = 'f87b7af2-ca8e-44fc-b754-444354b42fee';
+
+const gladys = {
+ job: {
+ wrapper: (type, func) => {
+ return async () => {
+ return func();
+ };
+ },
+ },
+ variable: {
+ getValue: fake.resolves('toto'),
+ },
+ event: {
+ emit: fake.returns(null),
+ },
+};
+
+describe('zigbee2mqttManager.publish', () => {
+ beforeEach(() => {
+ sinon.reset();
+ });
+
+ afterEach(() => {
+ sinon.reset();
+ });
+
+ it('should publish MQTT message', () => {
+ const mqttClient = {
+ publish: fake.returns(null),
+ };
+ const mqttLibrary = {
+ connect: fake.returns(mqttClient),
+ };
+ const zigbee2mqttManager = new Zigbee2mqttManager(gladys, mqttLibrary, serviceId);
+ zigbee2mqttManager.mqttClient = mqttClient;
+ zigbee2mqttManager.publish('toto', 'message');
+ assert.calledWith(mqttClient.publish, 'toto', 'message');
+ });
+ it('should publish MQTT message with error', () => {
+ const mqttClient = {
+ publish: (topic, message, random, cb) => {
+ cb('toto');
+ },
+ };
+ const mqttLibrary = {
+ connect: fake.returns(mqttClient),
+ };
+ const zigbee2mqttManager = new Zigbee2mqttManager(gladys, mqttLibrary, serviceId);
+ zigbee2mqttManager.mqttClient = mqttClient;
+ zigbee2mqttManager.publish('toto', 'mesage');
+ });
+ it('should not publish MQTT message', async () => {
+ const mqttLibrary = {
+ connect: fake.returns(null),
+ };
+ const zigbee2mqttManager = new Zigbee2mqttManager(gladys, mqttLibrary, serviceId);
+ try {
+ zigbee2mqttManager.publish('toto', 'mesage');
+ } catch (e) {
+ expect(e).instanceOf(ServiceNotConfiguredError);
+
+ return;
+ }
+
+ assert.fail();
+ });
+});
diff --git a/server/utils/constants.js b/server/utils/constants.js
index 891e1fbd94..bf5315ef89 100644
--- a/server/utils/constants.js
+++ b/server/utils/constants.js
@@ -55,6 +55,14 @@ const BUTTON_STATUS = {
SHORT_RELEASE: 49,
LONG_RELEASE: 50,
DOUBLE_PRESS: 51,
+ TOGGLE: 52,
+ TOGGLE_HOLD: 53,
+ BRIGHTNESS_UP_CLICK: 54,
+ BRIGHTNESS_UP_HOLD: 55,
+ BRIGHTNESS_UP_RELEASE: 56,
+ BRIGHTNESS_DOWN_CLICK: 57,
+ BRIGHTNESS_DOWN_HOLD: 58,
+ BRIGHTNESS_DOWN_RELEASE: 59,
};
const COVER_STATE = {
@@ -404,6 +412,9 @@ const ACTIONS = {
MQTT: {
SEND: 'mqtt.send',
},
+ ZIGBEE2MQTT: {
+ SEND: 'zigbee2mqtt.send',
+ },
MUSIC: {
PLAY_NOTIFICATION: 'music.play-notification',
},
@@ -480,6 +491,7 @@ const DEVICE_FEATURE_CATEGORIES = {
SWITCH: 'switch',
SPEED_SENSOR: 'speed-sensor',
TAMPER: 'tamper',
+ TELEINFORMATION: 'teleinformation',
TELEVISION: 'television',
TEMPERATURE_SENSOR: 'temperature-sensor',
THERMOSTAT: 'thermostat',
@@ -619,6 +631,7 @@ const DEVICE_FEATURE_TYPES = {
},
BUTTON: {
CLICK: 'click',
+ PUSH: 'push',
},
SIGNAL: {
QUALITY: 'integer',
@@ -686,6 +699,66 @@ const DEVICE_FEATURE_TYPES = {
INDEX: 'index',
DAILY_CONSUMPTION: 'daily-consumption',
},
+ TELEINFORMATION: {
+ BINARY: 'binary',
+ EAST: 'east',
+ EAIT: 'eait',
+ EASF01: 'easf01',
+ EASF02: 'easf02',
+ EASF03: 'easf03',
+ EASF04: 'easf04',
+ EASF05: 'easf05',
+ EASF06: 'easf06',
+ EASF07: 'easf07',
+ EASF08: 'easf08',
+ EASF09: 'easf09',
+ EASF10: 'easf10',
+ PREF: 'pref',
+ PCOUP: 'pcoup',
+ VTIC: 'vtic',
+ CCASN: 'ccasn',
+ CCASN_1: 'ccasn_1',
+ UMOY1: 'umoy1',
+ UMOY2: 'umoy2',
+ UMOY3: 'umoy3',
+ ERQ1: 'erq1',
+ ERQ2: 'erq2',
+ ERQ3: 'erq3',
+ ERQ4: 'erq4',
+ IRMS1: 'irms1',
+ IRMS2: 'irms2',
+ IRMS3: 'irms3',
+ URMS1: 'urms1',
+ URMS2: 'urms2',
+ URMS3: 'urms3',
+ EASD01: 'easd01',
+ EASD02: 'easd02',
+ EASD03: 'easd03',
+ EASD04: 'easd04',
+ NTARF: 'ntarf',
+ CCAIN: 'ccain',
+ CCAIN_1: 'ccain_1',
+ SINSTI: 'sinsti',
+ SMAXIN: 'smaxin',
+ SMAXIN_1: 'smaxin_1',
+ SMAXN: 'smaxn',
+ SMAXN2: 'smaxn2',
+ SMAXN3: 'smaxn3',
+ SINSTS: 'sinsts',
+ SINSTS2: 'sinsts2',
+ SINSTS3: 'sinsts3',
+ SMAXN_1: 'smaxn_1',
+ SMAXN2_1: 'smaxn2_1',
+ SMAXN3_1: 'smaxn3_1',
+ HHPHC: 'hhphc',
+ IMAX: 'imax',
+ ADPS: 'adps',
+ IMAX2: 'imax2',
+ IMAX3: 'imax3',
+ ADIR1: 'adir1',
+ ADIR2: 'adir2',
+ ADIR3: 'adir3',
+ },
SPEED_SENSOR: {
DECIMAL: 'decimal',
INTEGER: 'integer',