@mathquis/node-assistant-protocol
Version:
Assistant protocol decorator for Hermes protocol
774 lines (751 loc) • 27.7 kB
JavaScript
const File = require('fs')
const Path = require('path')
const UUID = require('uuid').v4
const Topics = require('./topics')
const Capabilities = require('./capabilities')
module.exports = (hermes, options) => {
options || (options = {})
const logger = options.logger || hermes.logger || console
// Traits
const loadable = require('./traits/loadable')(hermes, logger)
const stateful = require('./traits/stateful')(hermes, logger)
const failable = require('./traits/failable')(hermes, logger)
const volumeChangeable = require('./traits/volumeChangeable')(hermes, logger)
const volumeSetable = require('./traits/volumeSetable')(hermes, logger)
const volumeOffsetable = require('./traits/volumeOffsetable')(hermes, logger)
const muteSetable = require('./traits/muteSetable')(hermes, logger)
const muteChangeable = require('./traits/muteChangeable')(hermes, logger)
const applyMixins = (mixins, object) => {
return mixins.reduce((obj, [mixin, topic]) => {
return mixin(topic, obj)
}, object)
}
const assistant = {
Topics,
Capabilities,
dialogue: applyMixins([
[ loadable, Topics.DIALOGUE_LOAD ],
[ stateful, Topics.DIALOGUE_STATE ]
], {
name: 'Dialogue'
}
),
core: applyMixins([
[ loadable, Topics.CORE_LOAD ],
[ stateful, Topics.CORE_STATE ]
], {
name: 'Core'
}
),
brain: applyMixins([
[ loadable, Topics.BRAIN_LOAD ],
[ stateful, Topics.BRAIN_STATE ]
], {
name: 'Brain'
}
),
device: {
load: async (siteId) => {
logger.debug('Device on site "%s" is loaded', siteId)
await hermes.publish(hermes.format(Topics.DEVICE_LOAD, {siteId}), hermes.serialize({}))
},
onLoad: handler => {
const wrapper = (topic, payload) => {
let match
if ( match = topic.match(/^assistant\/device\/(.+?)\/load$/)) {
const [, siteId] = match
payload || (payload = {})
handler(topic, {...payload, siteId})
}
}
return hermes.on(hermes.format(Topics.DEVICE_LOAD, {siteId: '+'}), wrapper)
},
reboot: async (siteId) => {
id = UUID()
logger.debug('Requesting "%s" reboot on site "%s"', id, siteId)
await hermes.publish(hermes.format(Topics.DEVICE_REBOOT, {siteId}), hermes.serialize({id}))
},
onReboot: (siteId, handler) => {
const wrapper = (topic, payload) => {
let match
if ( match = topic.match(/^assistant\/device\/(.+?)\/reboot$/)) {
const [m, siteId] = match
handler(topic, {siteId, ...payload})
}
}
return hermes.on(hermes.format(Topics.DEVICE_REBOOT, {siteId}), wrapper)
},
shutdown: async (siteId) => {
id = UUID()
logger.debug('Requesting "%s" shutdown on site "%s"', id, siteId)
await hermes.publish(hermes.format(Topics.DEVICE_SHUTDOWN, {siteId}), hermes.serialize({id}))
},
onShutdown: (siteId, handler) => {
const wrapper = (topic, payload) => {
let match
if ( match = topic.match(/^assistant\/device\/(.+?)\/shutdown$/)) {
const [m, siteId] = match
handler(topic, {siteId, ...payload})
}
}
return hermes.on(hermes.format(Topics.DEVICE_SHUTDOWN, {siteId}), wrapper)
},
state: async (siteId, online = false, attributes = {}, state = {}) => {
logger.debug('Device "%s" state (online: %s)', siteId, online)
const payload = {
online,
siteId,
attributes,
state
}
const options = {
retain: true
}
await hermes.publish(hermes.format(Topics.DEVICE_STATE, {siteId}), hermes.serialize(payload), options)
},
onState: handler => {
const wrapper = (topic, payload) => {
let match
if ( match = topic.match(/^assistant\/device\/(.+?)\/state$/)) {
const [, siteId] = match
payload || (payload = {})
handler(topic, {...payload, siteId})
}
}
return hermes.on(hermes.format(Topics.DEVICE_STATE, {siteId: '+'}), wrapper)
},
getLastWill: siteId => {
return {
topic: hermes.format(Topics.DEVICE_STATE, {siteId}),
payload: hermes.serialize({online: false, attributes: {}, state: {}}),
retain: true
}
}
},
train: applyMixins([
[ failable, Topics.TRAIN_ERROR ]
], {
name: 'Train',
perform: async (dataset, timeout) => {
id = UUID()
logger.debug('Requesting training "%s"', id)
let p
if ( timeout ) p = hermes.train.waitForComplete(id, timeout)
await hermes.publish(Topics.TRAIN_PERFORM, hermes.serialize({
id, dataset
}))
await p
},
onPerform: handler => {
return on(Topics.TRAIN_PERFORM, handler)
},
complete: async (requestId) => {
logger.debug('Training "%s" complete', requestId)
await hermes.publish(Topics.TRAIN_COMPLETE, hermes.serialize({
requestId
}))
},
onComplete: (handler) => {
return on(Topics.TRAIN_COMPLETE, handler)
},
waitForComplete: (requestId, timeout) => {
logger.debug('Waiting for training "%s" completed for %d ms', requestId, timeout)
return waitFor(Topics.TRAIN_COMPLETE, (topic, payload) => {
if ( payload.requestId != requestId ) return
logger.debug('Training "%s" complete', requestId)
return true
}, timeout)
}
}
),
wakeword: {
keywordAudioData: async (keyword, siteId, audioData) => {
logger.debug('Sending detected keyword "%s" audio data', keyword)
await hermes.publish(hermes.format(Topics.WAKEWORD_KEYWORD_AUDIO_DATA, {keyword, siteId}), hermes.noop(audioData))
},
onKeywordAudioData: (keyword = '+', siteId = '+', handler) => {
const wrapper = (topic, payload) => {
let match
if ( match = topic.match(/^assistant\/wakeword\/(.+?)\/(.+?)\/audioData$/)) {
const [m, k, s] = match
handler(topic, {keyword: k, siteId: s, bytes: payload})
}
}
return hermes.on(hermes.format(Topics.WAKEWORD_KEYWORD_AUDIO_DATA, {keyword, siteId}), wrapper, hermes.noop)
}
},
alert: applyMixins([
[ failable, Topics.ALERT_ERROR ]
], {
name: 'Alert',
alertStarted: async (siteId, alert) => {
logger.debug('Alert "%s" started on site "%s"', alertId, siteId)
await hermes.publish(Topics.ALERT_ALERT_STARTED, hermes.serialize({
siteId, alert
}))
},
onAlertStarted: (handler) => {
return hermes.on(Topics.ALERT_ALERT_STARTED, handler)
},
setVolume: async (siteId, volume) => {
volume = parseInt(volume)
if ( isNaN(volume) ) throw new Error('Invalid volume "' + volume + '"')
volume = Math.max(0, Math.min(100, volume))
logger.debug('Setting alert volume on site "%s" to %d', siteId, volume)
await hermes.publish(Topics.ALERT_SET_VOLUME, hermes.serialize({
siteId, volume
}))
},
onSetVolume: (handler) => {
return hermes.on(Topics.ALERT_SET_VOLUME, handler)
},
volumeChanged: async (siteId, volume) => {
logger.debug('Alert volume on site "%s" changed to %d', siteId, volume)
await hermes.publish(Topics.ALERT_VOLUME_CHANGED, hermes.serialize({
siteId, volume
}))
},
onVolumeChanged: (handler) => {
return hermes.on(Topics.ALERT_VOLUME_CHANGED, handler)
},
setAlert: async (siteId, alert, timeout) => {
const requestId = UUID()
logger.debug('Requesting "%s" alert on site "%s"', requestId, siteId)
let p
if ( timeout ) p = assistant.alert.waitForSetAlertResult(requestId, timeout)
hermes.publish(Topics.ALERT_SET_ALERT, hermes.serialize({
requestId, siteId, alert
}))
await p
return requestId
},
onSetAlert: (handler) => {
return hermes.on(Topics.ALERT_SET_ALERT, handler)
},
waitForSetAlertResult: (id, timeout) => {
return hermes.waitForEither(
Topics.ALERT_SET_ALERT_SUCCEEDED,
(topic, payload) => payload.requestId === id,
Topics.ALERT_SET_ALERT_FAILED,
(topic, payload) => payload.requestId === id,
timeout
)
},
alertSet: async (siteId, alert) => {
logger.debug('Alert "%s" set on site "%s"', alertId, siteId)
await hermes.publish(Topics.ALERT_SET, hermes.serialize({
siteId, alert
}))
},
setAlertSucceeded: async (requestId, siteId) => {
logger.debug('Request "%s" has set alert successfully on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_SET_ALERT_SUCCEEDED, hermes.serialize({
requestId, siteId
}))
},
onSetAlertSucceeded: (handler) => {
return hermes.on(Topics.ALERT_SET_ALERT_SUCCEEDED, handler)
},
setAlertFailed: async (requestId, siteId, error) => {
logger.debug('Request "%s" failed setting alert on site "%s": error', requestId, siteId, error)
await hermes.publish(Topics.ALERT_SET_ALERT_FAILED, hermes.serialize({
requestId, siteId, error
}))
},
onSetAlertFailed: (handler) => {
return hermes.on(Topics.ALERT_SET_ALERT_FAILED, handler)
},
snoozeAlert: async (siteId, type, duration, timeout) => {
const requestId = UUID()
logger.debug('Request "%s" has asked to snooze alert on site "%s" for %d seconds', requestId, siteId, duration)
let p
if ( timeout ) p = assistant.alert.waitForSnoozeAlertResult(requestId, timeout)
hermes.publish(Topics.ALERT_SNOOZE_ALERT, hermes.serialize({
requestId, siteId, type, duration
}))
await p
return requestId
},
onSnoozeAlert: (handler) => {
return hermes.on(Topics.ALERT_SNOOZE_ALERT, handler)
},
waitForSnoozeAlertResult: (id, timeout) => {
return hermes.waitForEither(
Topics.ALERT_SNOOZE_ALERT_SUCCEEDED,
(topic, payload) => payload.requestId === id,
Topics.ALERT_SNOOZE_ALERT_FAILED,
(topic, payload) => payload.requestId === id,
timeout
)
},
alertSnoozed: async (siteId, alert) => {
logger.debug('Alert "%s" snoozed on site "%s"', alertId, siteId)
await hermes.publish(Topics.ALERT_ALERT_SNOOZED, hermes.serialize({
siteId, alert
}))
},
onAlertSnoozed: (handler) => {
return hermes.on(Topics.ALERT_ALERT_SNOOZED, handler)
},
snoozeAlertSucceeded: async (requestId, siteId) => {
logger.debug('Request "%s" has snoozed alert successfully on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_SNOOZE_ALERT_SUCCEEDED, hermes.serialize({
requestId, siteId
}))
},
onSnoozeAlertSucceeded: (handler) => {
return hermes.on(Topics.ALERT_SNOOZE_ALERT_SUCCEEDED, handler)
},
snoozeAlertFailed: async (requestId, siteId, error) => {
logger.debug('Request "%s" has failed to snooze alert on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_SNOOZE_ALERT_FAILED, hermes.serialize({
requestId, siteId, error
}))
},
onSnoozeAlertFailed: (handler) => {
return hermes.on(Topics.ALERT_SNOOZE_ALERT_FAILED, handler)
},
cancelAlert: async (siteId, type, period, timeout) => {
const requestId = UUID()
logger.debug('Request "%s" has asked to cancel alert on site "%s"', requestId, siteId)
let p
if ( timeout ) p = assistant.alert.waitForCancelAlertResult(requestId, timeout)
hermes.publish(Topics.ALERT_CANCEL_ALERT, hermes.serialize({
requestId, type, period
}))
await p
return requestId
},
onCancelAlert: (handler) => {
return hermes.on(Topics.ALERT_CANCEL_ALERT, handler)
},
waitForCancelAlertResult: (id, timeout) => {
return hermes.waitForEither(
Topics.ALERT_CANCEL_ALERT_SUCCEEDED,
(topic, payload) => payload.requestId === id,
Topics.ALERT_CANCEL_ALERT_FAILED,
(topic, payload) => payload.requestId === id,
timeout
)
},
alertCanceled: async (siteId, alert) => {
logger.debug('Alert "%s" canceled on site "%s"', alertId, siteId)
await hermes.publish(Topics.ALERT_ALERT_CANCELED, hermes.serialize({
siteId, alert
}))
},
onAlertCanceled: (handler) => {
return hermes.on(Topics.ALERT_ALERT_CANCELED, handler)
},
cancelAlertSucceeded: async (requestId, siteId) => {
logger.debug('Request "%s" has canceled alerts successfully on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_CANCEL_ALERT_SUCCEEDED, hermes.serialize({
requestId, siteId
}))
},
onCancelAlertSucceeded: (handler) => {
return hermes.on(Topics.ALERT_CANCEL_ALERT_SUCCEEDED, handler)
},
cancelAlertFailed: async (requestId, siteId, error) => {
logger.debug('Request "%s" has failed to cancel alerts on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_CANCEL_ALERT_FAILED, hermes.serialize({
requestId, siteId, error
}))
},
onCancelAlertFailed: (handler) => {
return hermes.on(Topics.ALERT_CANCEL_ALERT_FAILED, handler)
},
stopAlert: async (siteId, type, options, timeout) => {
const requestId = UUID()
logger.debug('Request "%s" has asked to stop alert on site "%s"', requestId, siteId)
let p
if ( timeout ) p = assistant.alert.waitForStopAlertResult(requestId, timeout)
hermes.publish(Topics.ALERT_STOP_ALERT, hermes.serialize({
requestId, siteId, type, options
}))
await p
return requestId
},
onStopAlert: (handler) => {
return hermes.on(Topics.ALERT_STOP_ALERT, handler)
},
waitForStopAlertResult: (id, timeout) => {
return hermes.waitForEither(
Topics.ALERT_STOP_ALERT_SUCCEEDED,
(topic, payload) => payload.requestId === id,
Topics.ALERT_STOP_ALERT_FAILED,
(topic, payload) => payload.requestId === id,
timeout
)
},
alertStopped: async (siteId, alert) => {
logger.debug('Alert "%s" stopped on site "%s"', alertId, siteId)
await hermes.publish(Topics.ALERT_ALERT_STOPPED, hermes.serialize({
siteId, alert
}))
},
onAlertStopped: (handler) => {
return hermes.on(Topics.ALERT_ALERT_STOPPED, handler)
},
stopAlertSucceeded: async (requestId, siteId) => {
logger.debug('Request "%s" has stopped alerts successfully on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_STOP_ALERT_SUCCEEDED, hermes.serialize({
requestId, siteId
}))
},
onStopAlertSucceeded: (handler) => {
return hermes.on(Topics.ALERT_STOP_ALERT_SUCCEEDED, handler)
},
stopAlertFailed: async (requestId, siteId, error) => {
logger.debug('Request "%s" has failed to stop alerts on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_STOP_ALERT_FAILED, hermes.serialize({
requestId, siteId, error
}))
},
onStopAlertFailed: (handler) => {
return hermes.on(Topics.ALERT_STOP_ALERT_FAILED, handler)
},
deleteAlert: async (siteId, type, options, timeout) => {
const requestId = UUID()
logger.debug('Request "%s" has asked to ddelete alert "%s" at "%s"', requestId, siteId)
let p
if ( timeout ) p = assistant.alert.waitForDeleteAlertResult(requestId, timeout)
hermes.publish(Topics.ALERT_DELETE_ALERT, hermes.serialize({
requestId, siteId, type, options
}))
await p
return requestId
},
onDeleteAlert: (handler) => {
return hermes.on(Topics.ALERT_DELETE_ALERT, handler)
},
waitForDeleteAlertResult: (id, timeout) => {
return hermes.waitForEither(
Topics.ALERT_DELETE_ALERT_SUCCEEDED,
(topic, payload) => payload.requestId === id,
Topics.ALERT_DELETE_ALERT_FAILED,
(topic, payload) => payload.requestId === id,
timeout
)
},
alertDeleted: async (siteId, alert) => {
logger.debug('Alert "%s" deleted on site "%s"', alertId, siteId)
await hermes.publish(Topics.ALERT_ALERT_DELETED, hermes.serialize({
siteId, alert
}))
},
onAlertDeleted: (handler) => {
return hermes.on(Topics.ALERT_ALERT_DELETED, handler)
},
deleteAlertSucceeded: async (requestId, siteId) => {
logger.debug('Request "%s" has deleted alerts successfully on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_DELETE_ALERT_SUCCEEDED, hermes.serialize({
requestId, siteId
}))
},
onDeleteAlertSucceeded: (handler) => {
return hermes.on(Topics.ALERT_DELETE_ALERT_SUCCEEDED, handler)
},
deleteAlertFailed: async (requestId, siteId, error) => {
logger.debug('Request "%s" has failed to delete alerts on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_DELETE_ALERT_FAILED, hermes.serialize({
requestId, siteId, error
}))
},
onDeleteAlertFailed: (handler) => {
return hermes.on(Topics.ALERT_DELETE_ALERT_FAILED, handler)
},
deleteAlerts: async (siteId, type, timeout) => {
const requestId = UUID()
logger.debug('Deleting alert "%s" on site "%s"', requestId, siteId)
let p
if ( timeout ) p = assistant.alert.waitForDeleteAlertsResult(requestId, timeout)
hermes.publish(Topics.ALERT_DELETE_ALERTS, hermes.serialize({
requestId, siteId, type
}))
await p
return requestId
},
onDeleteAlerts: (handler) => {
return hermes.on(Topics.ALERT_DELETE_ALERTS, handler)
},
waitForDeleteAlertsResult: (id, timeout) => {
return hermes.waitForEither(
Topics.ALERT_DELETE_ALERTS_SUCCEEDED,
(topic, payload) => payload.requestId === id,
Topics.ALERT_DELETE_ALERTS_FAILED,
(topic, payload) => payload.requestId === id,
timeout
)
},
deleteAlertsSucceeded: async (requestId, siteId) => {
logger.debug('Request "%s" has deleted alerts successfully on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_DELETE_ALERTS_SUCCEEDED, hermes.serialize({
requestId, siteId
}))
},
onDeleteAlertsSucceeded: (handler) => {
return hermes.on(Topics.ALERT_DELETE_ALERTS_SUCCEEDED, handler)
},
deleteAlertsFailed: async (requestId, siteId, error) => {
logger.debug('Request "%s" has failed to delete alerts on site "%s"', requestId, siteId)
await hermes.publish(Topics.ALERT_DELETE_ALERTS_FAILED, hermes.serialize({
requestId, siteId, error
}))
},
onDeleteAlertsFailed: (handler) => {
return hermes.on(Topics.ALERT_DELETE_ALERTS_FAILED, handler)
},
alertError: async (id, error, context) => {
logger.debug('Alert error:', error)
await hermes.publish(Topics.ALERT_ALERT_ERROR, serialize({
id,
error,
context
}))
},
onAlertError: handler => {
return on(Topics.ALERT_ALERT_ERROR, handler)
}
}
),
audioPlayer: applyMixins([
[ failable, Topics.AUDIO_PLAYER_ERROR ]
], {
name: 'AudioPlayer',
play: async (siteId, context, zone, timeout) => {
const requestId = UUID()
logger.debug('Audio player playing "%s" in zone "%s" from site "%s"', context.id, zone, siteId)
let p
if ( timeout ) p = assistant.audioPlayer.waitForPlayResult(requestId, timeout)
hermes.publish(Topics.AUDIO_PLAYER_PLAY, hermes.serialize({
requestId, siteId, context, zone
}))
await p
return requestId
},
onPlay: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PLAY, handler)
},
waitForPlayResult: (id, timeout) => {
return hermes.waitForEither(
Topics.AUDIO_PLAYER_PLAY_SUCCEEDED,
(topic, {requestId}) => requestId === id,
Topics.AUDIO_PLAYER_PLAY_FAILED,
(topic, {requestId}) => requestId === id,
timeout
)
},
playSucceeded: async (requestId) => {
logger.debug('Audio player playing "%s" succeeded', requestId)
await hermes.publish(Topics.AUDIO_PLAYER_PLAY_SUCCEEDED, hermes.serialize({
requestId
}))
},
onPlaySucceeded: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PLAY_SUCCEEDED, handler)
},
playFailed: async (requestId, error) => {
logger.debug('Audio player playing "%s" failed', requestId)
await hermes.publish(Topics.AUDIO_PLAYER_PLAY_FAILED, hermes.serialize({
requestId, error
}))
},
onPlayFailed: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PLAY_FAILED, handler)
},
pause: async (siteId, zone) => {
logger.debug('Audio player pausing site "%s" (zone: %s)', siteId, zone)
await hermes.publish(Topics.AUDIO_PLAYER_PAUSE, hermes.serialize({
siteId, zone
}))
},
onPause: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PAUSE, handler)
},
resume: async (siteId, zone) => {
logger.debug('Audio player resuming site "%s" (zone: %s)', siteId, zone)
await hermes.publish(Topics.AUDIO_PLAYER_RESUME, hermes.serialize({
siteId, zone
}))
},
onResume: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_RESUME, handler)
},
previous: async (siteId, zone) => {
logger.debug('Audio player previous on site "%s" (zone: %s)', siteId, zone)
await hermes.publish(Topics.AUDIO_PLAYER_PREVIOUS, hermes.serialize({
siteId, zone
}))
},
onPrevious: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PREVIOUS, handler)
},
next: async (siteId, zone) => {
logger.debug('Audio player next on site "%s" (zone: %s)', siteId, zone)
await hermes.publish(Topics.AUDIO_PLAYER_NEXT, hermes.serialize({
siteId, zone
}))
},
onNext: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_NEXT, handler)
},
seek: async (siteId, zone, position) => {
logger.debug('Audio player seeking on site "%s" to position %d (zone: %s)', siteId, position, zone)
await hermes.publish(Topics.AUDIO_PLAYER_SEEK, hermes.serialize({
siteId, zone, position
}))
},
onSeek: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_SEEK, handler)
},
offset: async (siteId, zone, offset) => {
logger.debug('Audio player offsetting on site "%s" with offset %d (zone: %s)', siteId, offset, zone)
await hermes.publish(Topics.AUDIO_PLAYER_OFFSET, hermes.serialize({
siteId, zone, offset
}))
},
onOffset: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_OFFSET, handler)
},
stop: async (siteId, zone) => {
logger.debug('Audio player stopping on zone "%s" from site "%s" (zone: %s)', zone, siteId, zone)
await hermes.publish(Topics.AUDIO_PLAYER_STOP, hermes.serialize({
siteId, zone
}))
},
onStop: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_STOP, handler)
},
setShuffle: async (siteId, zone, state) => {
state = !!state
logger.debug('Audio player setting shuffle on site "%s" to %s (zone: %s)', siteId, state, zone)
await hermes.publish(Topics.AUDIO_PLAYER_SET_SHUFFLE, hermes.serialize({
siteId, zone, state
}))
},
onSetShuffle: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_SET_SHUFFLE, handler)
},
setRepeat: async (siteId, zone, state) => {
state = !!state
logger.debug('Audio player setting repeat on site "%s" to %s (zone: %s)', siteId, state, zone)
await hermes.publish(Topics.AUDIO_PLAYER_SET_REPEAT, hermes.serialize({
siteId, zone, state
}))
},
onSetRepeat: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_SET_REPEAT, handler)
},
playbackStarted: async (siteId, state) => {
logger.debug('Audio player started playback of context "%s" on %s', state.id, siteId)
await hermes.publish(Topics.AUDIO_PLAYER_PLAYBACK_STARTED, hermes.serialize({
siteId, state
}))
},
onPlaybackStarted: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PLAYBACK_STARTED, handler)
},
playbackPaused: async (siteId, state) => {
logger.debug('Audio player paused playback of context "%s" on %s', state.id, siteId)
await hermes.publish(Topics.AUDIO_PLAYER_PLAYBACK_PAUSED, hermes.serialize({
siteId, state
}))
},
onPlaybackPaused: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PLAYBACK_PAUSED, handler)
},
playbackStopped: async (siteId) => {
logger.debug('Audio player stopped playback on %s', siteId)
await hermes.publish(Topics.AUDIO_PLAYER_PLAYBACK_STOPPED, hermes.serialize({
siteId
}))
},
onPlaybackStopped: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PLAYBACK_STOPPED, handler)
},
playbackProgress: async (siteId, state) => {
logger.debug('Audio player reported playback progress of context "%s" on %s', state.id, siteId)
await hermes.publish(Topics.AUDIO_PLAYER_PLAYBACK_PROGRESS, hermes.serialize({
siteId, state
}))
},
onPlaybackProgress: (handler) => {
return hermes.on(Topics.AUDIO_PLAYER_PLAYBACK_PROGRESS, handler)
}
}
),
speaker: applyMixins([
[ volumeSetable, Topics.SPEAKER_SET_VOLUME ],
[ volumeOffsetable, Topics.SPEAKER_OFFSET_VOLUME ],
[ volumeChangeable, Topics.SPEAKER_VOLUME_CHANGED ],
[ muteSetable, Topics.SPEAKER_SET_MUTE ],
[ muteChangeable, Topics.SPEAKER_MUTE_CHANGED ],
[ failable, Topics.SPEAKER_ERROR ]
], {
name: 'Speaker'
}
),
playback: applyMixins([
[ volumeSetable, Topics.PLAYBACK_SET_VOLUME ],
[ volumeOffsetable, Topics.PLAYBACK_OFFSET_VOLUME ],
[ volumeChangeable, Topics.PLAYBACK_VOLUME_CHANGED ],
[ muteSetable, Topics.PLAYBACK_SET_MUTE ],
[ muteChangeable, Topics.PLAYBACK_MUTE_CHANGED ],
[ failable, Topics.PLAYBACK_ERROR ]
], {
name: 'Playback'
}
),
voice: applyMixins([
[ loadable, Topics.VOICE_LOAD ],
[ stateful, Topics.VOICE_STATE ],
[ volumeSetable, Topics.VOICE_SET_VOLUME ],
[ volumeOffsetable, Topics.VOICE_OFFSET_VOLUME ],
[ volumeChangeable, Topics.VOICE_VOLUME_CHANGED ],
[ muteSetable, Topics.VOICE_SET_MUTE ],
[ muteChangeable, Topics.VOICE_MUTE_CHANGED ],
[ failable, Topics.VOICE_ERROR ]
], {
name: 'Voice'
}
),
doNotDisturb: applyMixins([
[ failable, Topics.DND_ERROR ]
], {
name: 'DnD',
toggleOn: async (siteId) => {
logger.debug('Setting do not disturb "ON" on site "%s"', siteId)
await hermes.publish(Topics.DND_TOGGLE_ON, hermes.serialize({
siteId
}))
},
onToggleOn: (handler) => {
return hermes.on(Topics.DND_TOGGLE_ON, handler)
},
toggleOff: async (siteId) => {
logger.debug('Setting do not disturb "OFF" on site "%s"', siteId)
await hermes.publish(Topics.DND_TOGGLE_OFF, hermes.serialize({
siteId
}))
},
onToggleOff: (handler) => {
return hermes.on(Topics.DND_TOGGLE_OFF, handler)
},
stateChanged: async (siteId, state) => {
logger.debug('Do not disturb state on site "%s" changed to %s', siteId, state)
await hermes.publish(Topics.DND_STATE_CHANGED, hermes.serialize({
siteId, state
}))
},
onStateChanged: (handler) => {
return hermes.on(Topics.DND_STATE_CHANGED, handler)
}
}
)
}
return {
...hermes,
assistant
}
}