/main.js |
@@ -1,24 +1,16 @@ |
#!/usr/bin/env nodejs |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2020 - License: GNU GPLv3 // |
// Copyright (C) Wizardry and Steamworks 2018 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
// Audioinjector cards: sysdefault:CARD=audioinjectorpi |
|
|
const Gpio = require('onoff').Gpio |
const mqtt = require('mqtt') |
const YAML = require('yamljs') |
const YAML = require('yamljs'); |
const winston = require('winston') |
const picoSpeaker = require('pico-speaker') |
const googleTTS = require('google-tts-api') |
const player = require('play-sound')((opts = { player: 'mpg123' })) |
const https = require('https') |
const tmp = require('tmp') |
const fs = require('fs') |
const lambda = require('was.js').lambda |
|
|
// Load configuration file. |
const config = YAML.load('config.yml') |
|
@@ -26,127 +18,55 @@ |
var picoConfig = { |
AUDIO_DEVICE: config.card, |
LANGUAGE: config.language |
} |
}; |
|
// Initialize with config |
picoSpeaker.init(picoConfig) |
|
// Generate GPIO pins for configuration. |
var ATTS = {} |
for (var i in config.GPIO) { |
if (!config.GPIO.hasOwnProperty(i)) continue |
|
if (config.GPIO[i] === -1) continue |
|
var ATTS = {}; |
for(var i in config.GPIO) { |
if(!config.GPIO.hasOwnProperty(i)) |
continue; |
|
if(config.GPIO[i] === -1) |
continue; |
|
ATTS[i] = new Gpio(config.GPIO[i], 'out') |
} |
|
|
// Set up logger. |
winston.add(winston.transports.File, { filename: config.log }) |
|
winston.add(winston.transports.File, {filename: config.log}) |
|
// Initiate connection to MQTT. |
const client = mqtt.connect(config.mqtt.url) |
|
function mqttSubscribeCallback (err, granted) { |
if (err) { |
winston.info(`Unable to subscribe to MQTT topic ${config.mqtt.topic}`) |
return |
} |
winston.info(`Subscribed to MQTT topic ${config.mqtt.topic}`) |
} |
|
client.on('connect', () => { |
winston.info(`Connected to MQTT server ${config.mqtt.url}`) |
client.subscribe(config.mqtt.topic, {}, mqttSubscribeCallback) |
const client = mqtt.connect(config.mqtt.url, {queueQoSZero: false}) |
|
client.on('connect', function () { |
winston.info('Connected to MQTT server') |
client.subscribe(config.mqtt.topic) |
}) |
|
client.on('error', () => { |
winston.error(`Unable to connect to MQTT server ${config.mqtt.url}`) |
}) |
|
client.on('message', (topic, message) => { |
if (message.length === 0) return |
|
|
client.on('message', function (topic, message) { |
if(message.length === 0) |
return; |
|
// Remove any retained message. |
client.publish(topic, '', { retain: true }) |
client.publish(topic, "", {retain: true}) |
|
message = message.toString() |
winston.info('Received message: ' + message) |
|
speakMessage = `${config.alexa}, Simon says, ${message.toString()}` |
winston.info(`Received MQTT message: ${message}`) |
|
if (config.tts.use === 'google' && speakMessage.length > 100) { |
winston.error( |
`Total spoken message would be too long: ${speakMessage.length} characters out of ${config.tts.google.maxLength}` |
) |
return |
} |
|
winston.info(`Sending to Alexa: ${speakMessage}`) |
ATTS['ptt'].write(1, err => { |
if (err) { |
winston.error(`Unable to press push-to-talk button: ${err}`) |
return |
ATTS["ptt"].write(1, (err) => { |
if(err) { |
winston.err('Unable to press push-to-talk button: ' + err.message) |
return; |
} |
|
lambda.switch( |
config.tts.use, |
tts => { |
winston.error(`Unknown TTS engine selected`) |
}, |
tts => tts === 'google', |
tts => { |
googleTTS(speakMessage, 'en', config.tts.google.speed) |
.then(url => { |
winston.info(`Google TTS URL obtained: ${url}`) |
// Send the message. |
picoSpeaker.speak(config.alexa + ", Simon says, " + message).then(function() { |
winston.info('Message ' + message + ' sent to Alexa.') |
|
tmp.tmpName((err, path) => { |
if (err) { |
winston.error(`Unable to create temporary file: ${err}`) |
return |
} |
|
const file = fs |
.createWriteStream(path) |
.on('error', err => { |
winston.error( |
`Writing temporary file ${path} failed with error ${err}` |
) |
}) |
.on('finish', () => { |
winston.info(`Google TTS file stored at ${path}`) |
winston.info(`Speaking...`) |
player.play(path, err => { |
if (err) { |
winston.error(`Unable to play the sound file: ${err}`) |
} |
ATTS['ptt'].write(0) |
winston.info(`Done`) |
}) |
}) |
.on('end', () => { |
file.close() |
}) |
|
https.get(url, (res, err) => { |
res.pipe(file) |
}) |
}) |
}) |
.catch(err => { |
winston.error(`Google TTS error: ${err}`) |
}) |
|
return true |
}, |
tts => tts === 'picotts', |
tts => { |
picoSpeaker.speak(speakMessage).then(() => { |
winston.info('Message ' + speakMessage + ' sent to Alexa.') |
|
ATTS['ptt'].write(0) |
}) |
|
return true |
} |
) |
ATTS["ptt"].write(0) |
}.bind(this)); |
}) |
}) |