Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Improve battery low notification #2245

Merged
merged 1 commit into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion server/config/brain/battery-threshold/answers.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 !"]
}
]
6 changes: 5 additions & 1 deletion server/config/brain/battery-threshold/answers.fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 !"]
}
]
26 changes: 25 additions & 1 deletion server/lib/device/device.checkBatteries.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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 = {
Expand Down
96 changes: 87 additions & 9 deletions server/test/lib/device/device.checkBatteries.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 = {
Expand All @@ -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();
Expand All @@ -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) => {
Expand All @@ -69,14 +112,49 @@ 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();

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);
});
});
Loading