node-red-contrib-smartnora
Version:
Google Smart Home integration via Smart Nora https://smart-nora.eu/
238 lines (237 loc) • 12.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const nora_firebase_common_1 = require("@andrei-tatar/nora-firebase-common");
const rxjs_1 = require("rxjs");
const media_device_1 = require("../nora/media-device");
const util_1 = require("./util");
module.exports = function (RED) {
RED.nodes.registerType('noraf-media', function (config) {
var _a, _b, _c, _d;
RED.nodes.createNode(this, config);
const noraConfig = RED.nodes.getNode(config.nora);
if (!(noraConfig === null || noraConfig === void 0 ? void 0 : noraConfig.valid)) {
return;
}
const deviceType = `action.devices.types.${config.deviceType}`;
if (!(0, nora_firebase_common_1.isDeviceType)(deviceType)) {
this.warn(`Device type not supported: ${deviceType}`);
return;
}
const deviceConfig = {
type: deviceType,
traits: [],
name: {
name: config.devicename,
},
roomHint: config.roomhint,
willReportState: true,
attributes: {},
state: {
online: true,
},
noraSpecific: {},
};
const asyncCommandExecution = [];
if (config.supportOnOff) {
deviceConfig.traits.push('action.devices.traits.OnOff');
if ((0, nora_firebase_common_1.isOnOff)(deviceConfig)) {
deviceConfig.state.on = false;
deviceConfig.noraSpecific.returnOnOffErrorCodeIfStateAlreadySet = !!config.errorifstateunchaged;
}
if (config.asyncCmdOnOff) {
asyncCommandExecution.push('action.devices.commands.OnOff');
}
}
if (config.supportVolume) {
deviceConfig.traits.push('action.devices.traits.Volume');
if ((0, nora_firebase_common_1.isVolumeDevice)(deviceConfig)) {
const volumeState = {
currentVolume: 40,
isMuted: false,
};
Object.assign(deviceConfig.state, volumeState);
const volumeAttributes = {
volumeCanMuteAndUnmute: !!config.volumeCanMuteAndUnmute,
volumeMaxLevel: 100,
levelStepSize: parseInt(config.volumeLevelStepSize, 10) || undefined,
};
Object.assign(deviceConfig.attributes, volumeAttributes);
}
if (config.asyncCmdVolume) {
asyncCommandExecution.push('action.devices.commands.setVolume', 'action.devices.commands.mute', 'action.devices.commands.volumeRelative');
}
}
if (config.supportMediaState) {
deviceConfig.traits.push('action.devices.traits.MediaState');
if ((0, nora_firebase_common_1.isMediaStateDevice)(deviceConfig)) {
const mediaState = {};
Object.assign(deviceConfig.state, mediaState);
const mediaStateAttributes = {
supportActivityState: config.supportActivityState,
supportPlaybackState: config.supportPlaybackState,
};
Object.assign(deviceConfig.attributes, mediaStateAttributes);
}
}
if (config.supportTransportControl && ((_a = config.transportControlCommands) === null || _a === void 0 ? void 0 : _a.length) > 0) {
deviceConfig.traits.push('action.devices.traits.TransportControl');
if ((0, nora_firebase_common_1.isTransportControlDevice)(deviceConfig)) {
const transportControlAttributes = {
transportControlSupportedCommands: config.transportControlCommands,
};
Object.assign(deviceConfig.attributes, transportControlAttributes);
}
if (config.asyncCmdTransportControl) {
asyncCommandExecution.push('action.devices.commands.mediaStop', 'action.devices.commands.mediaNext', 'action.devices.commands.mediaPrevious', 'action.devices.commands.mediaPause', 'action.devices.commands.mediaResume', 'action.devices.commands.mediaSeekRelative', 'action.devices.commands.mediaSeekToPosition', 'action.devices.commands.mediaRepeatMode', 'action.devices.commands.mediaShuffle', 'action.devices.commands.mediaClosedCaptioningOn', 'action.devices.commands.mediaClosedCaptioningOff');
}
}
const mediaInputs = config.mediaInputs;
if (config.supportInputSelector && (mediaInputs === null || mediaInputs === void 0 ? void 0 : mediaInputs.length) >= 1) {
deviceConfig.traits.push('action.devices.traits.InputSelector');
if ((0, nora_firebase_common_1.isInputSelectorDevice)(deviceConfig)) {
const inputSelectorAttributes = {
availableInputs: mediaInputs.map(i => ({
key: i.v,
names: [{
lang: config.language,
name_synonym: i.n.split(',').map(s => s.trim()),
}],
})),
orderedInputs: true,
};
Object.assign(deviceConfig.attributes, inputSelectorAttributes);
const inputSelectorState = {
currentInput: ((_b = mediaInputs.find(i => i.d)) !== null && _b !== void 0 ? _b : mediaInputs[0]).v,
};
Object.assign(deviceConfig.state, inputSelectorState);
}
if (config.asyncCmdInputSelector) {
asyncCommandExecution.push('action.devices.commands.SetInput', 'action.devices.commands.NextInput', 'action.devices.commands.PreviousInput');
}
}
const mediaApps = config.mediaApps;
if (config.supportAppSelector && (mediaApps === null || mediaApps === void 0 ? void 0 : mediaApps.length) >= 1) {
deviceConfig.traits.push('action.devices.traits.AppSelector');
if ((0, nora_firebase_common_1.isAppSelectorDevice)(deviceConfig)) {
const appSelectorAttributes = {
availableApplications: mediaApps.map(i => ({
key: i.v,
names: [{
lang: config.appsLanguage,
name_synonym: i.n.split(',').map(s => s.trim()),
}],
}))
};
Object.assign(deviceConfig.attributes, appSelectorAttributes);
const appSelectorState = {
currentApplication: (_d = (_c = mediaApps.find(i => i.d)) === null || _c === void 0 ? void 0 : _c.v) !== null && _d !== void 0 ? _d : 'unknown',
};
Object.assign(deviceConfig.state, appSelectorState);
}
if (config.asyncCmdAppSelector) {
asyncCommandExecution.push('action.devices.commands.appSelect', 'action.devices.commands.appSearch', 'action.devices.commands.appInstall');
}
}
const channels = config.mediaChannels;
if (config.supportChannel && (channels === null || channels === void 0 ? void 0 : channels.length) >= 1) {
deviceConfig.traits.push('action.devices.traits.Channel');
if ((0, nora_firebase_common_1.isChannelDevice)(deviceConfig)) {
const channelAttributes = {
availableChannels: channels.map(c => ({
key: c.k,
names: c.n.split(',').map(n => n.trim()),
number: c.i,
})),
};
Object.assign(deviceConfig.attributes, channelAttributes);
}
if (config.asyncCmdChannel) {
asyncCommandExecution.push('action.devices.commands.selectChannel', 'action.devices.commands.relativeChannel', 'action.devices.commands.returnChannel');
}
}
(0, util_1.registerNoraDevice)(this, RED, config, {
deviceConfig: Object.assign(Object.assign({}, deviceConfig), { noraSpecific: Object.assign(Object.assign({}, deviceConfig.noraSpecific), { asyncCommandExecution }) }),
updateStatus: ({ state, update }) => {
const states = [];
if (isOnOffState(state)) {
states.push(state.on ? 'on' : 'off');
}
if (isVolumeState(state)) {
states.push(state.isMuted ? 'mute' : `${state.currentVolume}`);
}
if (isMediaStateDeviceState(state)) {
if (state.activityState) {
states.push(state.activityState.toLowerCase());
}
if (state.playbackState) {
states.push(state.playbackState.toLowerCase());
}
}
if (isInputSelectorState(state)) {
states.push(state.currentInput);
}
if (isAppSelectorState(state)) {
states.push(state.currentApplication);
}
update(states.join(','));
},
mapStateToOutput: state => ({
payload: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (isOnOffState(state) ? { on: state.on } : null)), (isVolumeState(state) ? {
volume: state.currentVolume,
mute: state.isMuted,
} : null)), (isMediaStateDeviceState(state) ? {
activity: state.activityState,
playback: state.playbackState,
} : null)), (isInputSelectorState(state) ? {
input: state.currentInput,
} : null)), (isAppSelectorState(state) ? {
application: state.currentApplication,
} : null)),
}),
handleNodeInput: async ({ msg, updateState }) => {
await updateState(msg === null || msg === void 0 ? void 0 : msg.payload, [{
from: 'volume',
to: 'currentVolume',
}, {
from: 'mute',
to: 'isMuted',
}, {
from: 'activity',
to: 'activityState',
}, {
from: 'playback',
to: 'playbackState',
}, {
from: 'input',
to: 'currentInput',
}, {
from: 'application',
to: 'currentApplication',
}]);
},
customRegistration: device$ => device$.pipe((0, rxjs_1.switchMap)(d => d instanceof media_device_1.FirebaseMediaDevice
? d.mediaCommand$
: rxjs_1.EMPTY), (0, rxjs_1.tap)(command => {
this.send([null, {
payload: command,
topic: config.topic,
}]);
})),
});
function isOnOffState(state) {
return (0, nora_firebase_common_1.isOnOff)(deviceConfig) && 'on' in state;
}
function isMediaStateDeviceState(state) {
return (0, nora_firebase_common_1.isMediaStateDevice)(deviceConfig) && ('activityState' in state || 'playbackState' in state);
}
function isVolumeState(state) {
return (0, nora_firebase_common_1.isVolumeDevice)(deviceConfig) && 'currentVolume' in state;
}
function isInputSelectorState(state) {
return (0, nora_firebase_common_1.isInputSelectorDevice)(deviceConfig) && 'currentInput' in state;
}
function isAppSelectorState(state) {
return (0, nora_firebase_common_1.isAppSelectorDevice)(deviceConfig) && 'currentApplication' in state;
}
});
};