diff --git a/server/config/brain/battery-threshold/answers.en.json b/server/config/brain/battery-threshold/answers.en.json index ecefbfcb16..a23b027bce 100644 --- a/server/config/brain/battery-threshold/answers.en.json +++ b/server/config/brain/battery-threshold/answers.en.json @@ -2,7 +2,11 @@ { "label": "battery-threshold.success", "answers": [ - "Warning !!! Battery level on {{ device.name }} is under {{ value.min }}% (current: {{ value.current }}%)" + "Warning ! Battery level on {{ device.name }} is under {{ value.min }}% (current: {{ value.current }}%)" ] + }, + { + "label": "battery-level-is-low.success", + "answers": ["Warning ! Battery level on {{ device.name }} is low !"] } ] diff --git a/server/config/brain/battery-threshold/answers.fr.json b/server/config/brain/battery-threshold/answers.fr.json index 6b32f191bc..be60e19d4c 100644 --- a/server/config/brain/battery-threshold/answers.fr.json +++ b/server/config/brain/battery-threshold/answers.fr.json @@ -2,7 +2,11 @@ { "label": "battery-threshold.success", "answers": [ - "Avertissement !!! Le niveau de la batterie de {{ device.name }} est inférieur à {{ value.min }}% (actuel : {{ value.current }}%)" + "Avertissement ! Le niveau de la batterie de {{ device.name }} est inférieur à {{ value.min }}% (actuel : {{ value.current }}%)" ] + }, + { + "label": "battery-level-is-low.success", + "answers": ["Avertissement ! Le niveau de la batterie de {{ device.name }} est faible !"] } ] diff --git a/server/lib/device/device.checkBatteries.js b/server/lib/device/device.checkBatteries.js index bd5338fca4..f26c4b77fc 100644 --- a/server/lib/device/device.checkBatteries.js +++ b/server/lib/device/device.checkBatteries.js @@ -22,12 +22,14 @@ async function checkBatteries() { return; } + // Handle battery features const devices = await this.get({ device_feature_category: DEVICE_FEATURE_CATEGORIES.BATTERY }); devices.forEach((device) => { device.features .filter((feature) => { - return feature.last_value < minPercentBattery; + // We only take device with battery level < threshold + return feature.last_value !== null && feature.last_value < minPercentBattery; }) .forEach((feature) => { admins.forEach((admin) => { @@ -44,6 +46,28 @@ async function checkBatteries() { }); }); }); + + const deviceswithBatteryLowFeatures = await this.get({ + device_feature_category: DEVICE_FEATURE_CATEGORIES.BATTERY_LOW, + }); + + deviceswithBatteryLowFeatures.forEach((device) => { + device.features + .filter((feature) => { + // We only take devices with battery low === true + return feature.last_value === 1; + }) + .forEach((feature) => { + admins.forEach((admin) => { + const message = this.brain.getReply(admin.language, 'battery-level-is-low.success', { + device: { + name: device.name, + }, + }); + this.messageManager.sendToUser(admin.selector, message); + }); + }); + }); } module.exports = { diff --git a/server/test/lib/device/device.checkBatteries.test.js b/server/test/lib/device/device.checkBatteries.test.js index d540988156..3b379c89a7 100644 --- a/server/test/lib/device/device.checkBatteries.test.js +++ b/server/test/lib/device/device.checkBatteries.test.js @@ -5,7 +5,9 @@ const Device = require('../../../lib/device'); const StateManager = require('../../../lib/state'); const Job = require('../../../lib/job'); -const { SYSTEM_VARIABLE_NAMES } = require('../../../utils/constants'); +const Brain = require('../../../lib/brain'); +const { SYSTEM_VARIABLE_NAMES, DEVICE_FEATURE_TYPES, DEVICE_FEATURE_CATEGORIES } = require('../../../utils/constants'); +const db = require('../../../models'); const event = new EventEmitter(); const job = new Job(event); @@ -14,11 +16,12 @@ const user = { getByRole: stub().returns([{ selector: 'admin', language: 'fr' }]), }; -const messageManager = { - sendToUser: stub().returns(null), -}; - describe('Device check batteries', () => { + let brain; + before(async () => { + brain = new Brain(); + await brain.train(); + }); it('should do nothing if is not enabled', async () => { const stateManager = new StateManager(event); const service = { @@ -27,6 +30,9 @@ describe('Device check batteries', () => { const variables = { getValue: () => false, }; + const messageManager = { + sendToUser: stub().returns(null), + }; const device = new Device(event, messageManager, stateManager, service, {}, variables, job, {}, user); await device.checkBatteries(); @@ -47,19 +53,56 @@ describe('Device check batteries', () => { return undefined; }, }; + const messageManager = { + sendToUser: stub().returns(null), + }; const device = new Device(event, messageManager, stateManager, service, {}, variables, job, {}, user); await device.checkBatteries(); assert.notCalled(messageManager.sendToUser); }); - it('should send a message if battery is low', async () => { + it('should send a message if battery is lower than threshold', async () => { const stateManager = new StateManager(event); const service = { getService: () => null, }; - const brain = { - getReply: () => 'Avertissement !!! Le niveau de la batterie de Test device est inférieur à 30 % (actuel : 20 %)', + const variables = { + getValue: (key) => { + if (key === SYSTEM_VARIABLE_NAMES.DEVICE_BATTERY_LEVEL_WARNING_ENABLED) { + return true; + } + return 30; + }, + }; + const messageManager = { + sendToUser: stub().returns(null), + }; + const device = new Device(event, messageManager, stateManager, service, {}, variables, job, brain, user); + + await device.checkBatteries(); + + assert.calledWith( + messageManager.sendToUser, + 'admin', + 'Avertissement ! Le niveau de la batterie de Test device est inférieur à 30% (actuel : 20%)', + ); + }); + it('should send a message if battery is low', async () => { + // Update the feature to be a "battery low" feature + const feature = await db.DeviceFeature.findOne({ + where: { + selector: 'test-device-feature-battery', + }, + }); + await feature.update({ + last_value: 1, + category: DEVICE_FEATURE_CATEGORIES.BATTERY_LOW, + type: DEVICE_FEATURE_TYPES.BINARY, + }); + const stateManager = new StateManager(event); + const service = { + getService: () => null, }; const variables = { getValue: (key) => { @@ -69,6 +112,9 @@ describe('Device check batteries', () => { return 30; }, }; + const messageManager = { + sendToUser: stub().returns(null), + }; const device = new Device(event, messageManager, stateManager, service, {}, variables, job, brain, user); await device.checkBatteries(); @@ -76,7 +122,39 @@ describe('Device check batteries', () => { assert.calledWith( messageManager.sendToUser, 'admin', - 'Avertissement !!! Le niveau de la batterie de Test device est inférieur à 30 % (actuel : 20 %)', + 'Avertissement ! Le niveau de la batterie de Test device est faible !', ); }); + it('should do nothing is battery level is null', async () => { + // set the battery to null + const feature = await db.DeviceFeature.findOne({ + where: { + selector: 'test-device-feature-battery', + }, + }); + await feature.update({ + last_value: null, + last_value_changed: null, + }); + const stateManager = new StateManager(event); + const service = { + getService: () => null, + }; + const messageManager = { + sendToUser: stub().returns(null), + }; + const variables = { + getValue: (key) => { + if (key === SYSTEM_VARIABLE_NAMES.DEVICE_BATTERY_LEVEL_WARNING_ENABLED) { + return true; + } + return 30; + }, + }; + const device = new Device(event, messageManager, stateManager, service, {}, variables, job, {}, user); + + await device.checkBatteries(); + + assert.notCalled(messageManager.sendToUser); + }); });