preface
I’ve been reading a couple of articles lately, and I can’t help but feel like I’m not doing my raspberry PI job. So I thought, wow, I’ve got a whole morning wake-up call.
function
Every morning at 8 o ‘clock, the audio is played regularly (the audio content is the weather forecast and air quality of the day). After playing, the audio will be played at 8 o ‘clock tomorrow.
technology
Originally, I wanted to add a client, but I wanted to run a service directly to try node, so this article only need you know how to use JS on the line
- Node (Service)
- Iflytek Voice (to Audio)
- Play (play language)
- Aggregation API (Weather Forecast Interface)
- scheduleJob
The preparatory work
We need text recognition to convert to audio, and IFlytek can fuck for nothing
Xunfei sound
Please register your account in IFlytek and > Create application > Real name authentication
passport.xfyun.cn/
Then go to the console to find the service interface authentication information
The console. Xfyun. Cn/services/tt…
Find the key you need
Aggregate data
Weather forecast API, if you have other of course can also use other, this is also a useless fuck
I’m not going to focus on that
The website www.juhe.cn/
Weather forecast www.juhe.cn/docs/api/id…
Quick learning
Initialize the project
npm init -y
Copy the code
Then install the dependencies we need. Here are the versions of the dependencies
{
"name": "node-jiaoxing"."version": "1.0.0"."description": ""."main": "src/index.js"."scripts": {
"dev": "node src/index.js"
},
"author": ""."license": "ISC"."dependencies": {
"node-schedule": "^ 2.0.0." "."request": "^ 2.88.2"."websocket": "^ 1.0.31"}}Copy the code
Install dependencies
npm insatll
Copy the code
Create a lib folder
Create a lib folder and put the IFlytek resources that someone else has wrapped
index.js
const fs = require("fs");
const WebSocketClient = require('websocket').client;
const { getWssInfo, textToJson } = require('./util');
const xunfeiTTS = (auth, business, text, fileName, cb) = > {
let audioData = [];
const client = new WebSocketClient();
client.on('connect'.(con) = > {
con.on('error'.error= > {
throw (error);
});
con.on('close'.() = > {
const buffer = Buffer.concat(audioData);
fs.writeFile(fileName, buffer, (err) = > {
if (err) {
throw (err);
cb(err);
} else {
cb(null.'OK'); }}); }) con.on('message'.(message) = > {
if (message.type == 'utf8') {
const ret = JSON.parse(message.utf8Data);
audioData.push(Buffer.from(ret.data.audio, 'base64'));
if (ret.data.status == 2) { con.close(); }}});if (con.connected) {
constthejson = textToJson(auth, business, text); con.sendUTF(thejson); }}); client.on('connectFailed'.error= > {
throw (error);
});
const info = getWssInfo(auth);
client.connect(info.url);
}
module.exports = xunfeiTTS;
Copy the code
util.js
function btoa(text) {
return Buffer.from(text, "utf8").toString("base64");
}
function getWssInfo(auth, path = "/v2/tts", host = "tts-api.xfyun.cn") {
const { app_skey, app_akey } = auth;
const date = new Date(Date.now()).toUTCString();
const request_line = `GET ${path}HTTP / 1.1 `;
const signature_origin = `host: ${host}\ndate: ${date}\n${request_line}`;
let crypto = require("crypto");
const signature = crypto
.createHmac("SHA256", app_skey)
.update(signature_origin)
.digest("base64");
const authorization_origin = `api_key="${app_akey}",algorithm="hmac-sha256",headers="host date request-line",signature="${signature}"`;
const authorization = btoa(authorization_origin);
const thepath = `${path}? authorization=The ${encodeURIComponent(
authorization
)}&host=The ${encodeURIComponent(host)}&date=The ${encodeURIComponent(date)}`;
const final_url = `wss://${host}${thepath}`;
return { url: final_url, host: host, path: thepath };
}
function textToJson(auth, businessInfo, text) {
const common = { app_id: auth.app_id };
const business = {};
business.aue = "raw";
business.sfl = 1;
business.auf = "audio/L16; rate=16000";
business.vcn = "xiaoyan";
business.tte = "UTF8";
business.speed = 50;
Object.assign(business, businessInfo);
const data = { text: btoa(text), status: 2 };
return JSON.stringify({ common, business, data });
}
module.exports = {
btoa,
getWssInfo,
textToJson
};
Copy the code
Create SRC folder
Main entry file
index.js
// Import the path module
const path = require("path");
const { promisify } = require("util");
/ / xunfei TTS
const xunfeiTTS = require(".. /lib/index");
const tts = promisify(xunfeiTTS);
// Convert audio
const openGreetings = async (app_id, app_skey, app_akey, text) => {
const auth = { app_id, app_skey, app_akey };
// IFlytek API parameter configuration
https://www.xfyun.cn/doc/tts/online_tts/API.html / / interface document
const business = {
aue: "lame".// Audio encoding
sfl: 1.// Open stream return
speed: 50./ / speed
pitch: 50./ / high
volume: 100./ / volume
bgs: 0 // Background music
};
// The path to the file
const file = path.resolve('./src/good-morning.wav');
try {
// Execute the request
await tts(auth, business, text, file).then(res= > {});
} catch (e) {
console.log("test exception", e); }}; openGreetings('IFlytek APPID'.'Iflytek's APISecret'.'IFlytek APIKey'.'Good morning, handsome Yan Lao Shi.')
Copy the code
Test a wave
After executing NPM run dev, you can see that the good-morning.wav audio has been created under the SRC directory
Wearing headphones, can’t wait to open the audio, came good morning, handsome Yan Laoshi
Here we have completed the access of Iflytek voice, its main function is to convert text to audio
Modify greetings
We can’t always be in the morning
So we need to go by the system time
const greetings = {
"Seven and ten": ["Good morning."."Morning"]."11, 13.": ["Good afternoon."."Noon"]."14 or 17": ["Good afternoon"."Afternoon"]."18,": ["Good evening."."Night"],}const getTimeInfo = () = > {
const TIME = new Date(a)/ / (date) (month) (year)
let year = TIME.getFullYear()
let month = TIME.getMonth() + 1
let date = TIME.getDate()
/ / time
let hours = TIME.getHours()
let minutes = TIME.getMinutes()
// Generated greeting text
let greetingsStr = ""
// Iterate over the defined greeting data
for (const key in greetings) {
if(hours >= key.split(",") [0] && hours <= key.split(",") [1]) {
let greetingsKey = greetings[key]
greetingsStr = `${greetingsKey[0]}And is now${greetingsKey[1]}.${hours}Points,${minutes}Points `}}// Good afternoon, it is 12 noon, 12 o 'clock, today is August 28th, 2021
return `${greetingsStr}Is today,${year}Years,${month}Month,${date}Day `
}
Copy the code
So the data we have right now is good afternoon, it’s 12 o ‘clock, 12 o ‘clock, today is August 28th, 2021
When converting the audio, we can dynamically call getTimeInfo to get the current text and pass it to the audio
openGreetings('IFlytek APPID'.'Iflytek's APISecret'.'IFlytek APIKey', getTimeInfo())
Copy the code
Automatically play
Once I’ve created the audio, I want it to play right away
Introducing play resources
So we need to use a library play, Lao Yan also directly take the resources, and put them in the lib folder, called play.js
if(typeof exports= = ='undefined') {var play = {
sound: function ( wav ) {
debug.log(wav);
var e = $(The '#' + wav);
debug.log(e);
$('#alarm').remove();
$(e).attr('autostart'.true);
$('body').append(e);
returnwav; }}; }else{
var colors = require('colors'),
child_p = require('child_process'),
exec = child_p.exec,
spawn = child_p.spawn,
ee = require('events'),
util = require('util');
var Play = exports.Play = function Play() {
var self = this;
if(! (this instanceof Play)) {
return new Play();
}
ee.EventEmitter.call(this);
this.playerList = [
'afplay'.'mplayer'.'mpg123'.'mpg321'.'play',];this.playerName = false;
this.checked = 0;
var i = 0, child;
for (i = 0, l = this.playerList.length; i < l; i++) {
if (!this.playerName) {
(function inner (name) {
child = exec(name, function (error, stdout, stderr) {
self.checked++;
if(! self.playerName && (error ===null|| error.code ! = =127 )) {
self.playerName = name;
self.emit('checked');
return;
}
if (name === self.playerList[self.playerList.length-1]) {
self.emit('checked');
}
});
})(this.playerList[i]);
}
else {
break; }}}; util.inherits(Play, ee.EventEmitter); Play.prototype.usePlayer =function usePlayer (name) {
this.playerName = name;
}
Play.prototype.sound = function sound (file, callback) {
var callback = callback || function () {};
var self = this;
if (!this.playerName && this.checked ! = =this.playerList.length) {
this.on('checked'.function () {
self.sound.call(self, file, callback);
});
return false;
}
if (!this.playerName && this.checked === this.playerList.length) {
console.log('No suitable audio player could be found - exiting.'.red);
console.log('If you know other cmd line music player than these:'.red, this.playerList);
console.log('You can tell us, and will add them (or you can add them yourself)'.red);
this.emit('error'.new Error('No Suitable Player Exists'.red, this.playerList));
return false;
}
var command = [file],
child = this.player = spawn(this.playerName, command);
console.log('playing'.magenta + '= >'.yellow + file.cyan);
child.on('exit'.function (code, signal) {
if(code == null|| signal ! =null || code === 1) {
console.log('couldnt play, had an error ' + '[code: '+ code + '] ' + '[signal: ' + signal + ']] : ' + this.playerName.cyan);
this.emit('error', code, signal);
}
else if ( code == 127 ) {
console.log( self.playerName.cyan + ' doesn\'t exist! '.red );
this.emit('error', code, signal);
}
else if (code == 2) {
console.log(file.cyan + '= >'.yellow + 'could not be read by your player:'.red + self.playerName.cyan)
this.emit('error', code, signal);
}
else if (code == 0) {
console.log( 'completed'.green + '= >'.yellow + file.magenta);
callback();
}
else {
console.log( self.playerName.cyan + ' has an odd error with '.yellow + file.cyan);
console.log(arguments);
emit('error'); }});this.emit('play'.true);
return true; }}Copy the code
The use of play
In the SRC/index.js file
/ / player
const play = require('.. /lib/play').Play();
Copy the code
After converting the audio in openGreetings, play play.sound(file);
const openGreetings = async (app_id, app_skey, app_akey, text) => {
const auth = { app_id, app_skey, app_akey };
const business = {
aue: "lame".sfl: 1.speed: 50.pitch: 50.volume: 100.bgs: 0
};
const file = path.resolve("./src/good-morning.wav");
try {
await tts(auth, business, text, file).then(res= > {
// Perform playback
play.sound(file);
});
} catch (e) {
console.log("test exception", e); }};Copy the code
Test the
Run NPM run dev
Perform start, first to convert the audio, and then automatically start playing
With demand
After that, I need to play a piece of music that I like
This is very difficult for me. I have to pay more! “Add a hair. play.js has callback completed”
play.sound(file, function(){
// After the last one, we will start to play the song "Chick Chick" - Wang Rong
play.sound('./src/xiaojixiaoji.m4a')});Copy the code
This music resource should not be teaching, just pick and pull two of their favorite songs, common formats can be M4A, MP3, WAV and so on
If you are qualified, you can find a girl with a sweet voice and record an audio call to wake you up before playing the greeting for better effect
The weather forecast
Weather forecast, I use aggregated data here, of course if you have other weather forecast API can also, Mr. Yan here is just a simple example
/ / request
const request = require('request');
Copy the code
And then call
// Get the weather of the city
const city = "Changsha"
let text
request(`http://apis.juhe.cn/simpleWeather/query?city=The ${encodeURI(city)}&key= Aggregate data key '.(err, response, body) = > {
if(! err && response.statusCode ==200) {let res = JSON.parse(body).result.realtime
text = `
${getTimeInfo()}Here's the story${city}Real-time weather forecast, today, changsha weather for${res.info}Day, the outdoor temperature is${res.temperature}Degrees, the outdoor humidity is one percent${res.humidity}.${res.direct}.${res.power}After the weather report, play your favorite music
openGreetings('IFlytek APPID'.'Iflytek's APISecret'.'IFlytek APIKey', text)
}
}
)
Copy the code
That’s what the text looks like
Good afternoon, now is noon,12 o 'clock, 27, today is 2021, August 28, next for you to broadcast changsha real-time weather forecast, today, changsha weather is sunny, outdoor temperature is 27 degrees, outdoor humidity is 76 percent, south wind, level 3, the weather forecast is finished, next play your favorite musicCopy the code
Timing task
Why do we need scheduled tasks? Because our requirement is to play at 8:00 every morning, we use schedule
The schedule before also have said before, in a few months ago of the Node. Js automatically send E-mail | only twenty lines of code “is also mentioned in the email
Because we downloaded it earlier, we just need to import it
The introduction of
const schedule = require('node-schedule');
Copy the code
use
// The timer is executed at 8:00.00 every day
schedule.scheduleJob('0 0 8 * * *'.() = >{
request(`http://apis.juhe.cn/simpleWeather/query?city=The ${encodeURI(city)}&key= Aggregate data key '.(err, response, body) = > {
if(! err && response.statusCode ==200) {let res = JSON.parse(body).result.realtime
text = `
${getTimeInfo()}Here's the story${city}Real-time weather forecast, today, changsha weather for${res.info}Day, the outdoor temperature is${res.temperature}Degrees, the outdoor humidity is one percent${res.humidity}.${res.direct}.${res.power}After the weather report, play your favorite music
openGreetings('IFlytek APPID'.'Iflytek's APISecret'.'IFlytek APIKey', text)
}
}
)
});
Copy the code
Paste all the code in index.js
// Import the path module
const path = require("path");
const { promisify } = require("util");
/ / xunfei TTS
const xunfeiTTS = require(".. /lib/index");
const tts = promisify(xunfeiTTS);
/ / player
const play = require(".. /lib/play").Play();
/ / request
const request = require("request");
// Scheduled task
const schedule = require('node-schedule');
// Greetings and time
const greetings = {
"Seven and ten": ["Good morning."."Morning"]."11, 13.": ["Good afternoon."."Noon"]."14 or 17": ["Good afternoon"."Afternoon"]."18,": ["Good evening."."Night"]};const getTimeInfo = () = > {
const TIME = new Date(a);/ / (date) (month) (year)
let year = TIME.getFullYear();
let month = TIME.getMonth() + 1;
let date = TIME.getDate();
/ / time
let hours = TIME.getHours();
let minutes = TIME.getMinutes();
// Generated greeting text
let greetingsStr = "";
// Iterate over the defined greeting data
for (const key in greetings) {
if (hours >= key.split(",") [0] && hours <= key.split(",") [1]) {
let greetingsKey = greetings[key];
greetingsStr = `${greetingsKey[0]}And is now${greetingsKey[1]}.${hours}Points,${minutes}Points `; }}// Good afternoon, it is 12 noon, 12 o 'clock, today is August 28th, 2021
return `${greetingsStr}Is today,${year}Years,${month}Month,${date}Day `;
};
const openGreetings = async (app_id, app_skey, app_akey, text) => {
const auth = { app_id, app_skey, app_akey };
// IFlytek API parameter configuration
const business = {
aue: "lame".sfl: 1.speed: 50.pitch: 50.volume: 100.bgs: 0
};
// The path to the file
const file = path.resolve("./src/good-morning.wav");
try {
// Execute the request
await tts(auth, business, text, file).then(res= > {
play.sound(file, function() {
play.sound("./src/xiaojixiaoji.m4a");
});
});
} catch (e) {
console.log("test exception", e); }};const city = "Changsha";
let text;
schedule.scheduleJob("0 0 8 * * *".() = > {
request(
`http://apis.juhe.cn/simpleWeather/query?city=The ${encodeURI(city)}Key & key = polymerization `.(err, response, body) = > {
if(! err && response.statusCode ==200) {
let res = JSON.parse(body).result.realtime;
text = `
${getTimeInfo()}Here's the story${city}Real-time weather forecast, today, changsha weather for${res.info}Day, the outdoor temperature is${res.temperature}Degrees, the outdoor humidity is one percent${res.humidity}.${res.direct}.${res.power}After the weather report, play your favorite music;
openGreetings('IFlytek APPID'.'Iflytek's APISecret'.'IFlytek APIKey', text)
}
}
);
});
Copy the code
End and spend
At this point, executing NPM run dev is like setting off an alarm clock, but only if you ensure that the service doesn’t stop
That’s what woke me up this morning, but DON’t turn it up too loud
It was supposed to be on the Raspberry PI, but there was something wrong with the raspberry PI audio interface, so it didn’t work
Then I installed it on my computer
Full code link: pan.baidu.com/s/1aQXQSCB-… Password: dao7
Reference documentation
-
www.xfyun.cn/doc/tts/onl…
-
Github.com/Marak/play….
-
www.npmjs.com/package/xf-…