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

Chat: Enable switch control via user commands #2247

Merged
merged 2 commits into from
Mar 7, 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
22 changes: 22 additions & 0 deletions server/config/brain/switch/answers.en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"label": "switch.turn-on.success",
"answers": ["The switch is turned on !"]
},
{
"label": "switch.turn-on.fail",
"answers": ["I was unable to turn on the switch."]
},
{
"label": "switch.turn-off.success",
"answers": ["The switch is turned off !"]
},
{
"label": "switch.turn-off.fail",
"answers": ["I was unable to turn off the switch."]
},
{
"label": "switch.not-found",
"answers": ["I didn't find any switch with this name."]
}
]
22 changes: 22 additions & 0 deletions server/config/brain/switch/answers.fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"label": "switch.turn-on.success",
"answers": ["La prise est allumée !"]
},
{
"label": "switch.turn-on.fail",
"answers": ["Je n'ai pas réussi à allumer la prise."]
},
{
"label": "switch.turn-off.success",
"answers": ["La prise est éteinte !"]
},
{
"label": "switch.turn-off.fail",
"answers": ["Je n'ai pas réussi à éteindre la prise."]
},
{
"label": "switch.not-found",
"answers": ["Je n'ai pas trouvé de prise avec ce nom."]
}
]
12 changes: 12 additions & 0 deletions server/config/brain/switch/questions.en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"label": "switch.turn-on",
"questions": ["Turn on the switch %device%"],
"answers": ["Turning on the switch...", "I'm turning on the switch!"]
},
{
"label": "switch.turn-off",
"questions": ["Turn off the switch %device%"],
"answers": ["Turning off the switch...", "I'm turning off the switch!"]
}
]
12 changes: 12 additions & 0 deletions server/config/brain/switch/questions.fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"label": "switch.turn-on",
"questions": ["Allume la prise %device%"],
"answers": ["Allumage en cours...", "J'allume la prise !"]
},
{
"label": "switch.turn-off",
"questions": ["Eteins la prise %device%"],
"answers": ["Extinction en cours...", "J'éteins la prise !"]
}
]
2 changes: 2 additions & 0 deletions server/lib/device/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const CameraManager = require('./camera');
const LightManager = require('./light');
const TemperatureSensorManager = require('./temperature-sensor');
const HumiditySensorManager = require('./humidity-sensor');
const SwitchManager = require('./switch');

// Functions
const { add } = require('./device.add');
Expand Down Expand Up @@ -66,6 +67,7 @@ const DeviceManager = function DeviceManager(
this.lightManager = new LightManager(eventManager, messageManager, this);
this.temperatureSensorManager = new TemperatureSensorManager(eventManager, messageManager, this);
this.humiditySensorManager = new HumiditySensorManager(eventManager, messageManager, this);
this.switchManager = new SwitchManager(eventManager, stateManager, messageManager, this);

this.purgeStatesByFeatureId = this.job.wrapper(
JOB_TYPES.DEVICE_STATES_PURGE_SINGLE_FEATURE,
Expand Down
15 changes: 15 additions & 0 deletions server/lib/device/switch/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { INTENTS } = require('../../../utils/constants');
const { command } = require('./switch.command');

const SwitchManager = function SwitchManager(eventManager, stateManager, messageManager, deviceManager) {
this.eventManager = eventManager;
this.stateManager = stateManager;
this.messageManager = messageManager;
this.deviceManager = deviceManager;
this.eventManager.on(INTENTS.SWITCH.TURN_ON, this.command.bind(this));
this.eventManager.on(INTENTS.SWITCH.TURN_OFF, this.command.bind(this));
};

SwitchManager.prototype.command = command;

module.exports = SwitchManager;
51 changes: 51 additions & 0 deletions server/lib/device/switch/switch.command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const Promise = require('bluebird');

const { getDeviceFeature } = require('../../../utils/device');
const logger = require('../../../utils/logger');
const { NotFoundError } = require('../../../utils/coreErrors');
const { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES, STATE } = require('../../../utils/constants');

/**
* @description Command a switch.
* @param {object} message - The message sent by the user.
* @param {object} classification - The classification calculated by the brain.
* @param {object} context - The context object containing found variables in question.
* @returns {Promise} Resolve when the command was executed.
* @example
* light.command(message, classification, context);
*/
async function command(message, classification, context) {
const deviceEntity = classification.entities.find((entity) => entity.entity === 'device');
try {
if (!deviceEntity) {
throw new NotFoundError('Device not found');
}
const device = this.stateManager.get('device', deviceEntity.option);
if (!device) {
throw new NotFoundError('Device not found');
}
const deviceFeature = getDeviceFeature(
device,
DEVICE_FEATURE_CATEGORIES.SWITCH,
DEVICE_FEATURE_TYPES.SWITCH.BINARY,
);
if (!deviceFeature) {
throw new NotFoundError('Feature not found');
}
if (classification.intent === 'switch.turn-on') {
await this.deviceManager.setValue(device, deviceFeature, STATE.ON);
this.messageManager.replyByIntent(message, 'switch.turn-on.success', context);
} else if (classification.intent === 'switch.turn-off') {
await this.deviceManager.setValue(device, deviceFeature, STATE.OFF);
this.messageManager.replyByIntent(message, 'switch.turn-off.success', context);
}
} catch (e) {
logger.debug(e);
this.messageManager.replyByIntent(message, `${classification.intent}.fail`, context);
}
return null;
}

module.exports = {
command,
};
8 changes: 6 additions & 2 deletions server/lib/gateway/gateway.forwardMessageToOpenAI.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ const { Error429 } = require('../../utils/httpErrors');

const intentTranslation = {
SHOW_CAMERA: 'camera.get-image',
TURN_ON: 'light.turn-on',
TURN_OFF: 'light.turn-off',
TURN_ON: 'light.turn-on', // To be removed later, for backward compatibility
TURN_OFF: 'light.turn-off', // To be removed later, for backward compatibility
LIGHT_TURN_ON: 'light.turn-on',
LIGHT_TURN_OFF: 'light.turn-off',
SWITCH_TURN_ON: 'switch.turn-on',
SWITCH_TURN_OFF: 'switch.turn-off',
GET_TEMPERATURE: 'temperature-sensor.get-in-room',
GET_HUMIDITY: 'humidity-sensor.get-in-room',
SCENE_START: 'scene.start',
Expand Down
Loading
Loading