I have two Temp. Sensors on my Raspberry Pi and I have a node.js Express app. I want to create nedb databases dynamically of an array with sensor objects.
So I have an object with sensors in it:
sensors: [
{
name: "Indoor",
type: 22,
pin: 21
},
{
name: "Outdoor",
type: 22,
pin: 21
}
]};
Now I want to create for every Sensor three database:
databaseSetup(app.sensors);
function databaseSetup(sensor){
const dataStore = require('nedb');
const databaseVariables = [];
sensor.forEach((sensor) => {
const live = 'live' + sensor.name;
const seconds = 'seconds' + sensor.name;
const hours = 'hours' + sensor.name;
const test = {
live: new dataStore(`./databases/temp/${sensor.name}/live.db`),
seconds: new dataStore(`./databases/temp/${sensor.name}/seconds.db`),
hours: new dataStore(`./databases/temp/${sensor.name}/hours.db`) }
databaseVariables.push(test);
});
}
But this is not working. Can someone help me please?
I am not sure why you trying to do cause in my mind this is a bad practice. but you can make it dynamic. something like this:
const dt = require('nedb');
const db = [];
//USING LOOP and FUNCTION
let list = [{ name: "GasSensor" }, { name: "TempSensor" }];
let index = 0;
//BAD Practice
let setup = () => {
if (index + 1 > list.length) return;
let newInstance = new dt({ filename: 'nodejs/data/nedb_' + list[index].name, autoload: true });
console.log("Working on index " + (index + 1));
newInstance.loadDatabase((err) => {
if (err) {
//...
} else {
db.push(newInstance);
}
index++;
setup();
});
}
setup();
And also with API:
const exp = require("express");
const app = exp();
const dt = require('nedb');
const db = [];
app.get("/make/db/:name", (q, r) => {
//BAD PRACTICE
//JUST FOR TEST
let newInstance = new dt({ filename: 'nodejs/data/nedb_' + q.params.name, autoload: true });
newInstance.loadDatabase((err) => {
if (err) {
console.log(err + "");
r.send("ERROR");
}
else {
db.push(newInstance);
console.log("Database is loaded");
r.send("NEW DB CREATED");
}
});
});
app.listen(3000);
Related
I have a React.js and Node.js application where I have a Chart.js component whose objective is to show real-time data coming from Postgres database. The chart has a multi-select dropdown from where the user can choose at max 4 parameters and the query takes an array parameter(the array of 4 tags). I am new to sockets and I want to know how to handle socket connection for such a scenario. My code might be wrong entirely and I do not know where I am going wrong. Is it the approach or the logic? Should the query take an array of 4 parameters or should I re-write the query for single parameter? I am totally lost with the logic.
(Last time I tested with this logic, it was emitting the same data and not moving forward in real-time.)
// initialize socket
const io = require('socket.io')(httpServer, options);
// validate request
// eslint-disable-next-line arrow-body-style
io.use((socket, next) => {
// TODO validate token
// const token = socket.handshake.auth.token;
return next();
});
io.on('connection', (socket) => {
logger.info('socket connected');
socket.on('disconnect', (event) => {
logger.info('client disconnected', event);
});
socket.on('fetchChartData', async (obj) => {
const startTime1 = new Date();
let startTime = "";
let endTime = "";
if(startTime1.getSeconds() == 0) {
startTime = format(startTime1, 'yyyy-MM-dd HH:mm:ss');
endTime = format(new Date(startTime1.getTime() + (59 * 1000)), 'yyyy-MM-dd HH:mm:ss');
}
else {
const abc = startTime1.getTime() - (startTime1.getSeconds() * 1000)
const abc1 = startTime1.getTime() - (startTime1.getSeconds() * 1000) + 59000;
startTime = format(new Date(abc), 'yyyy-MM-dd HH:mm:ss');
endTime = format(new Date(abc1), 'yyyy-MM-dd HH:mm:ss');
}
// For converting array to string with parentheses
const arrToString = (oriArr) => {
let newStr = "";
const len = oriArr.length;
oriArr.forEach( (item, index) => {
newStr = newStr + "'"+ item + "'";
if(index < len -1) {
newStr = newStr + ",";
}
});
return newStr;
}
//const query = `select sr_datetime,tagid,tagvalue from md.taghda_${obj.siteid} where sr_datetime = '${startTime}' and tagid in (${arrToString(obj.tagArr)})`;
const query = `SELECT * FROM md.tag_summary_minute WHERE tagid in (${arrToString(obj.tagArr)}) AND bucket between '${startTime}' and '${endTime}'`;
const results = await dbService.executeQuery(query);
io.emit('CHART1RTANALYSIS', {
chartData: results.rows,
});
})
});
And this is my UI side socket code:
useEffect(() => {
if(selectedTagsID.length > 0) {
const socket = socketIOClient('http://localhost:3000', {
auth: {
token: Auth.getToken(),
},
});
const obj = {
tagArr: selectedTagsID,
siteid: resposeState?.selectedSite?.site
};
socket.emit('fetchChartData', obj);
console.log("The data is emitted every 59 seconds", obj);
socket.on("CHART1RTANALYSIS", (data) => {
console.log("chart data", data.chartData);
const chartData = data.chartData[0];
const userTimezone = resposeState?.selectedSite?.timezone
const dateInUserTimezone = userTimezone
? utcToZonedTime(chartData?.bucket, userTimezone)
: chartData?.bucket;
setServerEmittedData((state) => [
...state,
{
x: dateInUserTimezone,
y: chartData?.avg,
},
]);
});
socket.on("connect_error", (err) => {
console.log("connect error", err);
});
return () => {
socket.disconnect();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}
}, []);
console.log("Server emitted data is", serverEmittedData);
Please help me with this and also tell me if I should run a cron job for this since it is a chart. What should be the ideal approach? Running a cron job as long as the user is on this page or creating a new socket connection every time the user selects new tags so that the db query runs again.
I need help to get a simple query for MongoDB (SQL equivalent: "select speed from values"). But I can't find a solution for that.
Node.js backend for Vue.js
// a Part of Init-function:
await collection.replaceOne({}, {
speed: {
value: 65,
type: 2,
},
eightSpeed: {
value: 0.0043,
type: 2,
},
oSpeed: {
value: 0.31,
type: 2,
},
minusSpeed: {
value: 2.42,
type: 2,
}
}
//...
Now I need the query like this: http://192.168.220.220:3000/settings/getValue/speed to get an object speed.
const express = require("express");
const mongodb = require("mongodb");
const SettingsRouter = new express.Router();
SettingsRouter.get("/getValue/:value", async function (req, res) {
try {
const val = req.params.value; // req.body.text;
const select = {};
select[`${val}.value`] = 1;
console.log("settings.js:", "/getValue/:name", select);
const collection = await loadMongoCollection();
const value = await collection.findOne({},select)//.toArray();
res.status(201).send(value);
} catch (error) {
res.status(500).send("Failed to connect Database");
console.error("settings.js:", "/getValue/:name:", error);
}
});
async function loadMongoCollection() {
const dbUri = process.env.MONGODB_CONNSTRING || config.dbUri;
const MongoDB = process.env.MONGODB_DB || config.db;
try {
const client = await mongodb.MongoClient.connect(dbUri, {
useNewUrlParser: true,
});
const conn = client.db(MongoDB).collection("values");
return conn;
} catch (error) {
console.error("settings.js:", "loadMongoCollection:", error);
}
}
When I try it, I get all (not only the Speed Object) what I expected, or nothing.
What I do wrong?
EDIT 2022.01.06:
I try it to change my database:
data = {
speed: {
value: 65,
type: 2,
},//...
}
//...
await collection.replaceOne({}, {values:data}, { upsert: true });
And then the query:
const select = {[`values.${val}.value`]:"1"};
const where = {}; //{"values":val};
const value = await collection.find(where,select,).toArray();
But it will not work in rest... is there an issue in mongo package?
When I do it in https://cloud.mongodb.com - it works:
But my request returns all values...
Log shows:"'settings.js:', '/getValue/:name', { 'values.speed.value': '1' }"
In the screenshot you show the projection is values.speed.value, but in your endpoint you have:
const select = {};
select[`${val}.value`] = 1;
Which would evaluate to speed.value. To mimic what you have on the MongoDB console this should be:
const select = {};
select[`values.${val}.value`] = 1;
So, I changed my Frondend (vue) to spred all Values. I maked some Helper Functions:
CheckForChangedObj
check two object for changes
updateObj
copy all data from object into another
export function CheckForChangedObj(targetObject, obj) {
if (targetObject === typeof undefined || targetObject == {}) {
return true
}
if (JSON.stringify(targetObject) !== JSON.stringify(obj)) {
return true
}
return false
}
export function updateObj(targetObject, obj) {
let keys = Object.keys(obj)
for (let k in keys) {
try {
let key = keys[k]
if (!targetObject.hasOwnProperty(key)) {
//define target, if not exist
targetObject[key] = {}
}
//Workaround for References
if (obj[key].hasOwnProperty("__v_isRef")) {
if (targetObject[key].hasOwnProperty("__v_isRef")) {
targetObject[key].value = obj[key].value
} else {
targetObject[key] = obj[key].value
}
} else {
//Source i a Norm Value
//check for an Object inside, then go in...
if ("object" === typeof obj[key] && !Array.isArray(obj[key])) {
updateObj(targetObject[key], obj[key]) // recurse
} else {
//not else-if!!! __v_isRef: true
if (targetObject[key].hasOwnProperty("__v_isRef")) {
targetObject[key].value = obj[key]
} else {
targetObject[key] = obj[key]
}
}
}
} catch (error) {
console.log(
"key:",
keys[k],
"Error:",
error
)
}
}
}
Then spreading...
import {updateObj,CheckForChangedObj } from "../tools/tools"
beforeMount() {
this.getAllValuesAPI()
setInterval(() => {
this.checkForChanges()
// ml("TABLE", this.values)
}, 10000)
},
setup() {
let prevValues = {}
let values = {
speed: {
id:1,
type: SettingType.Slider,
value: ref(0)
}
//...
}
function checkForChanges() {
//intervaled function to get changes from API
let changed = CheckForChangedObj(this.values, this.prevValues)
if (changed) {
updateObj(this.prevValues, this.values)
setValuesToAPI()
}
else{
getAllValuesFromAPI()
}
}
async function getAllValuesFromAPI() {
//get ALL Settings-Data from API, and put them in values
const res = await axios.get(`settings/getAll`)
return updateObj(this.values, res.data[0].values) u
}
}
When you have a better solution, please help...
I built simple weather webpage basing on the tutorial. and I have a webpage with below JS code;
I have also Node JS code( on the bottom) for temperature and pressure sensor written with Johnny-Five. This works perfectly but what I wanna do is display readouts from the sensors setup with NodeJS on the webpage. What is the best approach to do that? I tried to setup this with websocket but it was not really working.
let weather = {
apiKey: "xxxxxxxxxxxxxx",
fetchWeather: function (city) {
fetch(
"https://api.openweathermap.org/data/2.5/weather?q=" + city + "&units=metric&appid=" + this.apiKey
).then((response) => {
return response.json();
})
.then((data) => this.displayWeather(data));
},
displayWeather: function (data) {
const { name } = data;
const { icon, description } = data.weather[0];
const { temp, humidity, pressure } = data.main;
const { speed } = data.wind;
const temperatura = Math.round(temp);
document.querySelector(".miasto").innerText = "Pogoda w " + name;
document.querySelector(".icon").src =
"https://openweathermap.org/img/wn/" + icon + ".png";
document.querySelector(".opis").innerText = description;
document.querySelector(".temperatura").innerText = temperatura + "°C";
document.querySelector(".wilgotnosc").innerText =
"Wilgotność: " + humidity + "%";
document.querySelector(".cisnienie").innerText =
"Ciśnienie: " + pressure + "HPa";
document.querySelector(".wiatr").innerText =
"Prędkość wiatru: " + speed + " km/h";
document.querySelector(".pogoda").classList.remove("loading");
document.body.style.backgroundImage =
"url('https://source.unsplash.com/1600x900/?" + name + "')";
},
search: function () {
this.fetchWeather(document.querySelector(".search-bar").value);
},
};
document.querySelector(".search button").addEventListener("click", function () {
weather.search();
});
document
.querySelector(".search-bar")
.addEventListener("keyup", function (event) {
if (event.key == "Enter") {
weather.search();
}
});
weather.fetchWeather("Katowice");
var five = require("johnny-five");
var board = new five.Board(
{
port: "COM4"
}
);
board.on("ready", function() {
var multi = new five.Multi({
controller: "BMP180",
freq: 500
});
multi.on("change", function() {
console.log("Termometr");
console.log(" Temperatura : ", this.thermometer.celsius, " ℃");
console.log("--------------------------------------");
var pressure2 = Math.round(this.barometer.pressure*100, 1)/10;
console.log("Barometr");
console.log(" Ciśnienie : ", pressure2, " HPa" );
console.log("--------------------------------------");
});
});
I managed to solve the issue. Quite simple but mybe it will help someone here
Data which I am sending are
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 8085 })
var obj = {
press: "69",
temp: "24"
}
wss.on("connection", ws => {
ws.send(JSON.stringify(obj));
} );
And I get it:
const ws = new WebSocket("ws://localhost:8085");
ws.addEventListener("open", () => {
console.log("We are connected");
ws.addEventListener("message", (data) => {
console.log(JSON.parse(data.data));
});
});
I have been trying to follow this official guide from IBM (https://developer.ibm.com/tutorials/add-a-trigger-word-to-your-watson-assistant/) to build a Nodejs voice assistant that answer after it recognizes a "wake up word". That guide seems a little bit outdated so I decided to use it with Assistant V2 and ibm-watson 5.2.0 package from npm.
I am getting a WebSocket connection error with not much information on it, the issue seems to be on line 33 and with the params I am sending to the 'recognizeUsingWebsocket' method. Am I missing something along this parameters?
const AssistantV2 = require('ibm-watson/assistant/v2');
const TextToSpeechV1 = require('ibm-watson/text-to-speech/v1');
const SpeechToTextV1 = require('ibm-watson/speech-to-text/v1');
const { IamAuthenticator } = require('ibm-watson/auth');
const mic = require('mic');
const conversation = new AssistantV2({
authenticator: new IamAuthenticator({ apikey: '<api_key>' }),
url: 'https://gateway-lon.watsonplatform.net/assistant/api/',
version: '2018-09-19'
});
const speechToText = new SpeechToTextV1({
authenticator: new IamAuthenticator({ apikey: '<api_key>' }),
serviceUrl: 'https://gateway-lon.watsonplatform.net/speech-to-text/api'
});
const textToSpeech = new TextToSpeechV1({
authenticator: new IamAuthenticator({ apikey: '<api_key>' })
});
const micParams = {
rate: 44100,
channels: 2,
debug: true,
exitOnSilence: 6
};
const microphone = mic(micParams);
const micInputStream = microphone.getAudioStream();
const textStream = micInputStream
.pipe(
speechToText.recognizeUsingWebSocket({
accessToken:'<access_token>',
contentType: 'audio/l16; rate=44100; channels=2',
interimResults: true,
inactivityTimeout: -1
})
)
.setEncoding('utf8');
const speakResponse = (text) => {
var params = {
text: text,
accept: 'audio/wav',
voice: 'en-US_AllisonVoice'
};
var writeStream = fs.createWriteStream('output.wav');
textToSpeech
.synthesize(params)
.then((audio) => {
audio.pipe(writeStream);
})
.catch((err) => {
console.log('error:', err);
});
writeStream.on('finish', function() {
ffprobe('output.wav', function(err, probeData) {
if (probeData) {
pauseDuration = probeData.format.duration;
microphone.pause();
speaker.play('output.wav');
startTime = new Date();
}
});
});
writeStream.on('error', function(err) {
console.log('Text-to-speech streaming error: ' + err);
});
};
function printContext(header) {
if (debug) {
console.log(header);
if (context.system) {
if (context.system.dialog_stack) {
const util = require('util');
console.log(" dialog_stack: ['" + util.inspect(context.system.dialog_stack, false, null) + "']");
}
}
}
}
function watsonSays(response) {
if (typeof response !== 'undefined') {
console.log('Watson says:', response);
}
}
function isActive(text) {
var elapsedTime = new Date() - startTime;
if (elapsedTime > SLEEP_TIME) {
// go to sleep
startTime = new Date();
botIsActive = false;
}
if (botIsActive) {
// in active conversation, so stay awake
startTime = new Date();
return true;
} else {
// we are asleep - did we get a wake up call?
if (text.toLowerCase().indexOf(wakeWord) > -1) {
// time to wake up
console.log('App just woke up');
botIsActive = true;
} else {
// false alarm, go back to sleep
console.log('App needs the wake up command');
}
return botIsActive;
}
}
function performConversation() {
console.log('App is listening, you may speak now.');
textStream.on('data', (user_speech_text) => {
userSpeechText = user_speech_text.toLowerCase();
console.log('\n\nApp hears: ', user_speech_text);
if (isActive(user_speech_text)) {
conversation.message(
{
assistantId: process.env.ASSISTANT_ID,
sessionId: process.env.SESSION_ID,
input: { text: user_speech_text }
},
(err, response) => {
console.log(err);
context = response.context;
watson_response = response.output.text[0];
if (watson_response) {
speakResponse(watson_response);
}
watsonSays(watson_response);
}
);
}
});
}
microphone.start();
performConversation();
It seems that you do not use the right endpoint for websockets :
note : api endpoints have had a new version in dec 2019
you use :
https://gateway-lon.watsonplatform.net/speech-to-text/api
and it should be something like : (i think the prefix wss is key)
wss://api.{location}.speech-to-text.watson.cloud.ibm.com/instances/{instance_id}/v1/recognize
cf Api reference : https://cloud.ibm.com/apidocs/speech-to-text/speech-to-text#websocket_methods
I know, this is something old. There are many questions regarding to this. But none of them didn't guide me or didn't gave me the actual concept.
My case is:
if something
render something
else
render somethingAnother
Why is this logic generates this error enter image description here
After 1st execution, I'm not able to continue this process (I could continue for a while, but after some time error will come), by pressing back button of browser and then returning back to the home page. Everytime I should restart my server using node command. Why headers won't reset if I press back button of browser, how to do some header reset or something which will correct my logic.
const cv = require('opencv4nodejs');
var async = require('async');
var OrderID;
var OrderNo;
var compare = 0;
var CompanyName;
var notSimilar = 0;
const download = require('image-downloader')
const distanceThreshold = 30;
var url;
var FolderPath;
var isSimilar = 0;
var j = 0;
var image1;
var dbPath;
var filterCount = 0;
var image2;
var dbImgCount = 0;
var express = require('express');
var request = require('request');
var app = express();
app.set('view engine', 'pug')
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).single('userPhoto');
const sql = require("mssql");
var config = {
user: '***',
password: '****',
server: '192.168.5.100\\SQLEXPRESS',
database: 'Test_MatdesignDB1',
connectionTimeout: 300000,
requestTimeout: 300000,
pool: {
idleTimeoutMillis: 300000,
max: 100
}
};
sql.connect(config).then(pool => {
return pool.request()
.query('select count(*) from OrderImageUpload; select FolderPath from OrderImageUpload;')
}).then(result => {
var a = JSON.stringify(result.recordset[0]);
dbImgCount = a.slice(4,6);
FolderPath = result.recordsets[1];
sql.close();
}).catch(err => {
console.log(err);
sql.close();
})
app.get('/',function(req,res){
res.sendFile(__dirname + "/index.html");
});
app.post('/api/photo',function(req,res){
compare = 1;
upload(req,res,function(err) {
if(err) {
console.log(err);
res.send("File uploading error");
}
else{
// console.log("Success");
image1 = req.file.filename;
var matchFeatures = ({ url, img1, img2, detector, matchFunc }) => {
// detect keypoints
const keyPoints1 = detector.detect(img1);
const keyPoints2 = detector.detect(img2);
// compute feature descriptors
const descriptors1 = detector.compute(img1, keyPoints1);
const descriptors2 = detector.compute(img2, keyPoints2);
// match the feature descriptors
const matches = matchFunc(descriptors1, descriptors2);
// only keep good matches
const bestN = 40;
const bestMatches = matches.sort(
(match1, match2) => (match1.distance - match2.distance)
).slice(0, bestN);
//console.log(bestMatches);
for(var i=0; i<bestN; i++){
if((bestMatches[i].distance) <= (distanceThreshold)){
filterCount++;
}
}
if(filterCount >= (bestN/4))
isSimilar = 1;
if(isSimilar){
notSimilar = 0;
filterCount = 0;
isSimilar = 0;
console.log("Similar images\n");
dbPath = url;
sql.close();
(async function() {
try {
let pool = await sql.connect(config)
let result1 = await pool.request()
.query("select OrderID from Test_MatdesignDB1.dbo.OrderImageUpload where FolderPath = '"+dbPath+"';")
OrderID = result1.recordset[0].OrderID;
let result2 = await pool.request()
.query('select OrderNo , CompanyName from Test_MatdesignDB1.dbo.[Order] where OrderID = '+OrderID);
OrderNo = result2.recordset[0].OrderNo;
CompanyName = result2.recordset[0].CompanyName;
res.render('similar', { title: 'Similar', CompanyName: CompanyName, OrderID: OrderID, OrderNo: OrderNo, img_path_var : dbPath }) //Render number 1 in 'if' case
} catch (err) {
console.log(err);
sql.close();
}
sql.close();
})()
sql.on('error', err => {
console.log(err);
})
}
else{
isSimilar = 0;
filterCount = 0;
notSimilar++;
if(notSimilar >= (dbImgCount ))
{
notSimilar = 0;
res.render('notSimilar', { title: 'Not Similar', message: 'No Similar Images' }) //Render number 2 in 'else' case
}
console.log("Not similar\n");
}
return cv.drawMatches(
img1,
img2,
keyPoints1,
keyPoints2,
bestMatches
);
};
for (j=0; j<dbImgCount; j++) {
(function(j) {
async.waterfall([
async function downloadIMG(done) {
try {
var options = {
url: FolderPath[j].FolderPath,
dest: '/home/ubuntu/imgCompare/DBimages/'
}
const { filename, image } = await download.image(options);
return [filename, options.url];
} catch (e) {
console.error(e)
}
},
async function featureMatching([a, MatchURL], done){
const img1 = cv.imread(image1);
url = MatchURL;;
const img = a.slice(33);
const img2 = cv.imread('./DBimages/'+img);
const orbMatchesImg = matchFeatures({
url,
img1,
img2,
detector: new cv.ORBDetector(),
matchFunc: cv.matchBruteForceHamming
});
done(null);
}
],
function (err) {});
})(j);
}
}
});
});
app.listen(5000,function(){
console.log("Working on port 5000");
});
You need to add return before rendering a view. It's happening because the view rendering is happening more than 1 time there must be a condition in your code which is letting views to render multiple times. Add this return statement:
return res.render();
You're getting this error because you're calling matchFeatures() multiple times within a for loop.
app.post('/api/photo', function (req, res) {
var matchFeatures = ({url, img1, img2, detector, matchFunc}) => {
if (isSimilar) {
res.render('similar', {
title: 'Similar',
...
}) //Render number 1 in 'if' case
} else {
res.render('notSimilar', {
title: 'Not Similar',
message: 'No Similar Images'
}) //Render number 2 in 'else' case
}
};
for (j = 0; j < dbImgCount; j++) {
async function featureMatching() {
const orbMatchesImg = matchFeatures({ // since you're calling it multiple times here
url, // matchFeatures() will attempt to send
img1, // responses multiple times
img2,
detector: new cv.ORBDetector(),
matchFunc: cv.matchBruteForceHamming
});
}
}
});
To fix this, You need to consolidate all these responses and send to client only once.
I figured out the error. I didn't reset the variable notSimilar at the entry point.
Done resetting of notSimilar as below, no error! Thanks Everyone.
app.post('/api/photo',function(req,res){
notSimilar = 0;