I have built a Google Smart Home Action using the Local Fulfillment SDK as outlined in the following articles:
https://developers.google.com/assistant/smarthome/develop/local
https://github.com/actions-on-google/create-local-home-app
I am using UDP for device discovery and my Google Nest Hub can successfully scan and detect the virtual device running on my laptop as well as download the JS of the local app.
My Local Home SDK configuration is as follows - Local Home SDK Configuration.
When the Nest Hub executes the IDENTIFY intent of my app handler I am receiving the following error(s):
[smarthome.DeviceManager] Intent handler failed with error: Buffer is not defined
[smarthome.DeviceManager] Got a rejected promise Buffer is not defined
This appears to be a Node.JS error as opposed to something specific to the local SDK app itself. Below is the code of my local app.
/// <reference types="#google/local-home-sdk" />
import App = smarthome.App;
import Constants = smarthome.Constants;
import DataFlow = smarthome.DataFlow;
import Execute = smarthome.Execute;
import Intents = smarthome.Intents;
import IntentFlow = smarthome.IntentFlow;
const SERVER_PORT = 3388;
interface ILightParams {
on?: boolean,
brightness?: number
}
class LocalExecutionApp {
constructor(private readonly app: App) { }
identifyHandler(request: IntentFlow.IdentifyRequest):
Promise<IntentFlow.IdentifyResponse> {
console.log("IDENTIFY intent: " + JSON.stringify(request, null, 2));
const scanData = request.inputs[0].payload.device.udpScanData;
console.log("SCANDATA: " + JSON.stringify(scanData));
if (!scanData) {
const err = new IntentFlow.HandlerError(request.requestId, 'invalid_request', 'Invalid scan data');
return Promise.reject(err);
}
const localDeviceId = Buffer.from(scanData.data, 'hex');
console.log("ScanData Local Device: " + localDeviceId);
const response: IntentFlow.IdentifyResponse = {
intent: Intents.IDENTIFY,
requestId: request.requestId,
payload: {
device: {
// id: localDeviceId.toString(),
id: 'sample-device',
verificationId: localDeviceId.toString(),
}
}
};
console.log("IDENTIFY response: " + JSON.stringify(response, null, 2));
return Promise.resolve(response);
}
executeHandler(request: IntentFlow.ExecuteRequest):
Promise<IntentFlow.ExecuteResponse> {
console.log("EXECUTE intent: " + JSON.stringify(request, null, 2));
const command = request.inputs[0].payload.commands[0];
const execution = command.execution[0];
const response = new Execute.Response.Builder()
.setRequestId(request.requestId);
const promises: Promise<void>[] = command.devices.map((device) => {
console.log("Handling EXECUTE intent for device: " + JSON.stringify(device));
// Convert execution params to a string for the local device
const params = execution.params as ILightParams;
const payload = this.getDataForCommand(execution.command, params);
// Create a command to send over the local network
const radioCommand = new DataFlow.HttpRequestData();
radioCommand.requestId = request.requestId;
radioCommand.deviceId = device.id;
radioCommand.data = JSON.stringify(payload);
radioCommand.dataType = 'application/json';
radioCommand.port = SERVER_PORT;
radioCommand.method = Constants.HttpOperation.POST;
radioCommand.isSecure = false;
console.log("Sending HTTP request to the smart home device:", payload);
return this.app.getDeviceManager()
.send(radioCommand)
.then(() => {
const state = {online: true};
response.setSuccessState(device.id, Object.assign(state, params));
console.log(`Command successfully sent to ${device.id}`);
})
.catch((e: IntentFlow.HandlerError) => {
e.errorCode = e.errorCode || 'invalid_request';
response.setErrorState(device.id, e.errorCode);
console.error('An error occurred sending the command', e.errorCode);
});
});
return Promise.all(promises)
.then(() => {
return response.build();
})
.catch((e) => {
const err = new IntentFlow.HandlerError(request.requestId, 'invalid_request', e.message);
return Promise.reject(err);
});
}
/**
* Convert execution request into a local device command
*/
getDataForCommand(command: string, params: ILightParams): unknown {
switch (command) {
case 'action.devices.commands.OnOff':
return {
on: params.on ? true : false
};
default:
console.error('Unknown command', command);
return {};
}
}
}
const localHomeSdk = new App('1.0.0');
const localApp = new LocalExecutionApp(localHomeSdk);
localHomeSdk
.onIdentify(localApp.identifyHandler.bind(localApp))
.onExecute(localApp.executeHandler.bind(localApp))
.listen()
.then(() => console.log('Ready'))
.catch((e: Error) => console.error(e));
Any insight on why this error is occurring is greatly appreciated.
Cheers.
Reposting the answer in the comments:
Buffer is not a type that is directly supported in a browser environment. You can see this for yourself by trying to run something like x = new Buffer() in your web browser's dev console.
To support a class like Buffer, you can use a bundling tool like Webpack. In the official sample, you can see an example Webpack configuration. Other bundling tools can also be used, and examples can be found in the official Local Home scaffolding tool or can be called directly with an npm init command.
npm init #google/local-home-app app/ --bundler webpack
npm init #google/local-home-app app/ --bundler rollup
npm init #google/local-home-app app/ --bundler parcel
Related
Can someone please tell me what is wrong in my code before I go back to MongoDB?
Project is in Node.js (Next.js)
This is how I set firebase (it works for authentication with Google Login for instance):
import { initializeApp } from 'firebase/app';
const credentials = {
...
}
const firebase = initializeApp(credentials);
export default firebase;
then this is my api js file where it throws error "db.ref" is not a function:
import firebase from '#/firebase/firebase'
import { getDatabase, ref, onValue, update, child, orderByChild, equalTo, once } from "firebase/database"
export default async (req, res) => {
const db = getDatabase(firebase);
if (req.method === 'POST') {
const body = req.body
const playlistTracks = body.playlist
const playlistName = body.name
const uid = body.uid
const data = ...
console.log(data)
var ref = db.ref().child('users');
ref.child(uid).orderByChild('n').equalTo(playlistName).once("child_added", function(snapshot) {
let listId = snapshot.key;
db.ref("users/" + uid + "/" + listId).update(data);
res.send({ risp : 'ok' })
});
}
}
realtime database structure is:
- users
- <user uid>
- <playlist uid>
c: []
n: "playlist name"
so I'm trying to first retrieve the correct playlist by it's name ("n" value) comparing all "n" with the name of the given playlist, then I'd need to update (overwrite) it with my object (data)
UPDATE:
So I found the other methods Web version 9 (modular) in the documentation, as suggested by Frank van Puffelen below, but it now thorws a error
#firebase/database: FIREBASE WARNING: Exception was thrown by user
callback. Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they
are sent to the client
My code now is like this:
try {
const myQuery = query(ref(db, 'users/' + uid), orderByChild('n'), equalTo(playlistName));
onChildAdded(myQuery, (data) => {
let listId = data.key;
const updates = {};
updates["users/" + uid + "/" + listId] = dataToUpdate;
update(ref(db), updates);
}, {
onlyOnce: true
});
res.send({ risp : 'ok' })
} catch (e) {
res.status(400).end();
}
also tried like this, but it's the same error:
const myQuery = query(ref(db, 'users/' + uid), orderByChild('n'), equalTo(playlistName));
onChildAdded(myQuery, (data) => {
let listId = data.key;
update(ref(db, "users/" + uid + "/" + listId), dataToUpdate)
.then(() => {
res.send({ risp: 'ok' })
})
.catch((error) => {
res.status(400).end();
});
}, {
onlyOnce: true
});
You're using the new modular API, so can't use namespaced accessors like db.ref() anymore. Instead use ref(db, 'users').
I highly recommend keeping the documentation handy while upgrading this code to the new API version, as it has example of the modular and namespaced API side by side. The upgrade guide is probably also a worthwhile read).
I'm trying to make a request to the KuCoin API to query the balance. I'm using the NodeJS API found here but I keep getting the error whenever I execute the code.
And here's the code snippet
data().then(api => {
const apiKey = api.api_key;
const apiSecretKey = api.api_secret;
const contactId = api.contact_id;
const exchange = api.exchange;
const passphrase = 'Passphrase';
/** Init Configure */
const config =
{
key: apiKey, // KC-API-KEY
secret: apiSecretKey, // API-Secret
passphrase: passphrase, // KC-API-PASSPHRASE
environment: "live"
}
API.init(require(config));
if (apiKey && exchange === "KuCoin-Futures") {
console.log("KuCoin Balance")
async function getBalance() {
try {
let r = await API.getAccountOverview()
console.log(r.data)
} catch(err) {
console.log(err)
}
}
return getBalance()
}
});
I the console log I get the following error
TypeError: request.charAt is not a function
at Function.Module._resolveLookupPaths (internal/modules/cjs/loader.js:617:15)
Does anyone know how I can fix this??
There are couple of things which look weird in the code snippet you provided, but the sample code from the kucoin-node-api library you linked should work perfectly fine. In case you are using that one, try this snippet which should show your account info:
const api = require('kucoin-node-api');
const config = {
apiKey: 'YOUR_KUCOIN_API_KEY',
secretKey: 'YOUR_KUCOIN_API_SECRET',
passphrase: 'YOUR_KUCOIN_API_PASSPHRASE',
environment: 'live'
};
api.init(config);
api.getAccounts().then((r) => {
console.log(r.data);
}).catch((e) => {
console.log(e);
});
In case you're using a different library, kucoin-node-sdk maybe (judging by your code snippet), then try to configure it correctly:
config.js file:
module.exports = {
baseUrl: 'https://api.kucoin.com',
apiAuth: {
key: 'YOUR_KUCOIN_API_KEY',
secret: 'YOUR_KUCOIN_API_SECRET',
passphrase: 'YOUR_KUCOIN_API_PASSPHRASE'
},
authVersion: 2
}
and your main.js (or whatever the name is):
const API = require('kucoin-node-sdk');
API.init(require('./config'));
const main = async () => {
const getTimestampRl = await API.rest.Others.getTimestamp();
console.log(getTimestampRl.data);
};
main();
The code above will show you KuCoin server timestamp only, but should be enough to keep going.
Good luck with trading!
Basically, my code worked completely fine in replit, but now it doesnt work in a vsc folder. my replit version also suddenly can’t send any messages anymore. it sends all the console.logs but the client.say stuff it just skips without an error.
const tmi = require('tmi.js');
// Define configuration options
const opts = {
identity: {
username: 'BormBot',
password: 'cut out for a reason'
},
channels: [
'Epicurious__'
]
};
// Create a client with our options
const client = new tmi.client(opts);
const jsonFile = require('./link.json');
const fs = require('fs');
const mongoose = require('mongoose');
// Register our event handlers (defined below)
client.on('connected', onConnectedHandler);
// Connect to Twitch:
client.connect();
client.on('message', (channel, tags, msg, self, target) => {
if (self) return;
//start of geoguessr commands
const link = {
"link": ""
};
if (msg.startsWith('!geolink')) {
if (tags.badges.broadcaster == 1) {
const arguments = msg.split(/[ ]+/)
if (arguments[1]) {
let link = arguments[1];
const data = JSON.stringify(link);
fs.writeFile('./link.json', data, (err) => {
if (err) {
throw err;
}
console.log("JSON data is saved.");
});
client.say(channel, link);
} else {
console.log("no args");
}
}
}
if (msg.startsWith('!game')) {
// read JSON object from file
fs.readFile('./link.json', 'utf-8', (err, data) => {
if (err) {
throw err;
}
// parse JSON object
const linkDone = JSON.parse(data.toString());
// print JSON object
client.say(channel, `The link for the current geoguessr game is: ${linkDone}`);
console.log(`${linkDone}`);
});
}
//end of geoguessr commands
});
// Called every time the bot connects to Twitch chat
function onConnectedHandler(addr, port) {
console.log(`* Connected to ${addr}:${port}`);
}
console
Also on twitch developer forum: 2
On twitch developer forum there hasn't been an answer yet, hence why I'm also putting it on here. Hopefully I can find an answer, also, maybe add a tag for tmi.js
I am getting the following errors when running my application in elastic beanstalk: [error] 3636#0: *295 upstream prematurely closed connection while reading response header from upstream and [error] 3636#0: *295 connect() failed (111: Connection refused) while connecting to upstream Its strange because if I hit those routes independently it works fine. It only appears to error when firing those routes from my vuex action.
The following is the log from the AWS elastic beanstalk.
The following is the network tab when it hits my FFmpeg route:
The following is the generate video action as fired from vuex.
async [GENERATE_VIDEO]({state, rootState, dispatch, commit}){
const username = rootState.user.currentUser.username;
const s3Id = rootState.templates.currentVideo.stock_s3_id;
const type = rootState.dataClay.fileFormat || state.type;
const vid = new Whammy.fromImageArray(state.captures, 30);
vid.lastModifiedDate = new Date();
vid.name = "canvasVideo.webm";
const data = new FormData();
const id = `${username}_${new Date().getTime()}`;
data.append("id", id);
data.append("upload", vid);
const projectId = await dispatch(INSERT_PROJECT);
await dispatch(UPLOAD_TEMP_FILE, data);
const key = await dispatch(CONVERT_FILE_TYPE, { id, username, type, projectId});
const role = rootState.user.currentUser.role;
state.file = `/api/files/${key}`;
let message;
if(role!='banner'){
message =`<p>Your video is ready.</p> Download`;
} else {
message = `<p>Your video is ready. You may download your file from your banner account</p>`;
const resolution = rootState.dataClay.matrix[0];
await dispatch(EXPORT_TO_BANNER, { s3Id, fileUrl: key, extension: `.${type}`, resolution});
}
And here are the api routes called in the actions.
async [UPLOAD_TEMP_FILE]({ commit }, data) {
try {
const response = await axios.post("/api/canvas-editor/upload-temp", data);
return response.data;
} catch (error) {
console.log(error);
}
},
async [CONVERT_FILE_TYPE]({commit}, data) {
try{
const response = await axios.post("/api/canvas-editor/ffmpeg", data);
return response.data;
} catch(error){
console.log(error);
}
}
}
As I said all my routes work and the application runs as expected on localhost however when uploaded to aws I receive unexpected errors.
After some digging I found out that I did not set the ffmpeg path.
Once this was done it worked great.
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('#ffmpeg-installer/ffmpeg').path;
ffmpeg.setFfmpegPath(ffmpegPath);
module.exports = ffmpeg;
I am using the npm package react-native-fetch-blob.
I have followed all the steps from the git repository to use the package.
I then imported the package using the following line:
var RNFetchBlob = require('react-native-fetch-blob');
I am trying to request a BLOB containing an image from the a server.
This is my main method.
fetchAttachment: function(attachment_uri) {
var authToken = 'youWillNeverGetThis!'
var deviceId = '123';
var xAuthToken = deviceId+'#'+authToken
//Authorization : 'Bearer access-token...',
// send http request in a new thread (using native code)
RNFetchBlob.fetch('GET', config.apiRoot+'/app/'+attachment_uri, {
'Origin': 'http://10.0.1.23:8081',
'X-AuthToken': xAuthToken
})
// when response status code is 200
.then((res) => {
// the conversion is done in native code
let base64Str = res.base64()
// the following conversions are done in js, it's SYNC
let text = res.text()
let json = res.json()
})
// Status code is not 200
.catch((errorMessage, statusCode) => {
// error handling
});
}
I keep receiving the following error:
"Possible Unhandled Promise Refection(id: 0): TypeError: RNFetchBlob.fetch is not a function".
Any ideas?
The issue is you are using ES5 style require statements with a library written against ES6/ES2015. You have two options:
ES5:
var RNFetchBlob = require('react-native-fetch-blob').default
ES6:
import RNFetchBlob from 'react-native-fetch-blob'
My import looks like this : import RNFetchBlob from 'rn-fetch-blob';
but I'v got an error : TypeError: RNFetchBlob.scanFile is not a function
My code:
const downloadAudio = async () => {
const { config, fs } = RNFetchBlob;
const meditationFilesPath =
Platform.OS == 'android'
? `${fs.dirs.DownloadDir}/meditations/${id}`
: `${fs.dirs.DocumentDir}/meditations/${id}`;
let audio_URL = track;
let options = {
fileCache: true,
path: meditationFilesPath + `/${id}.mp3`,
addAndroidDownloads: {
// Related to the Android only
useDownloadManager: true,
notification: true,
path: meditationFilesPath + `/${id}.mp3`,
description: 'Audio',
},
};
try {
const resAudio = await config(options).fetch('GET', audio_URL.uri);
if (resAudio) {
const audio = await RNFetchBlob.fs.scanFile([
{ path: resAudio.path(), mime: 'audio/mpeg' },
]);
console.log('res -> ', audio);
Alert.alert('Audio Downloaded Successfully.');
}
} catch (error) {
console.error('error from downloadAudio', error);
}
};