Can't get Flask-socketIO to work on Raspberry Pi Zero - flask-socketio

I'm trying to stream sensor (MPU9250) data from a Raspberry Pi, but I can't get Flask-socketIO to send data to the client. It serves the webpage, but nothing afterwards.
Here's the code - I've stripped out the sensor related code.
Once the page has initially loaded, I don't get any console.log messages, and the page seems to stop responding - e.g. if I click the refresh button, it just hangs. After some time I get a warning saying that 'WebSocket connection to..... failed: WebSocket is closed before the connection is established"
I've been messing with this for the past few days to no avail. I've tried a tonne of things, but nothing has helped.
Any advice would be appreciated.
MPU9250.py
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
import smbus
import time
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
async_mode = 'eventlet'
socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode)
### SENSOR CODE HERE
# Define a route for the HTML page
#app.route('/')
def index():
return render_template('index.html')
# Define a socketio event for streaming the MPU9250 data
#socketio.on('connect')
def stream():
while True:
# Read the acceleration and magnetometer data from MPU9250
accel_xout = read_word_2c(accel_xout_h)
accel_yout = read_word_2c(accel_yout_h)
accel_zout = read_word_2c(accel_zout_h)
mag_xout = read_word_2c(mag_xout_h)
mag_yout = read_word_2c(mag_yout_h)
mag_zout = read_word_2c(mag_zout_h)
#Print outputs:
print("X Accel: ", accel_xout, " | Y Accel: ", accel_yout, " | Z_Accel: ", accel_zout)
# Stream the acceleration and magnetometer data to the web page for plotting
socketio.emit('acceleration', {'x': time.time(), 'y': accel_xout})
socketio.emit('magnetometer', {'x': time.time(), 'y': mag_xout})
socketio.send('Test message')
time.sleep(0.1)
if __name__ == '__main__':
socketio.run(app, debug=True, port=80, host='0.0.0.0')
index.html
<!DOCTYPE html>
<html>
<head>
<title>MPU9250 Sensor Data</title>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js" integrity="sha512-aMGMvNYu8Ue4G+fHa359jcPb1u+ytAF+P2SCb+PxrjCdO3n3ZTxJ30zuH39rimUggmTwmh2u7wvQsDTHESnmfQ==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var socket = io();
socket.on('connect', function() {
socket.emit('my_event', {data: 'I\'m connected!'});
});
socket.on('my_response', function(msg, cb) {
$('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());
if (cb)
cb();
});
});
</script>
</head>
<body>
<h1>MPU9250 Sensor Stream</h1>
<h2>Acceleration</h2>
<div id="acceleration-graph"></div>
<h2>Magnetometer</h2>
<div id="magnetometer-graph"></div>
<script type="text/javascript" charset="utf-8">
console.log("Here");
const accelerationData = {
x: [],
y: [],
mode: "lines",
name: "Acceleration",
};
const magnetometerData = {
x: [],
y: [],
mode: "lines",
name: "Magnetometer",
};
const accelerationLayout = {
title: "Acceleration Data",
xaxis: { title: "Time" },
yaxis: { title: "Acceleration (raw)" },
};
const magnetometerLayout = {
title: "Magnetometer Data",
xaxis: { title: "Time" },
yaxis: { title: "Magnetic field (raw)" },
};
const accelerationPlot = Plotly.newPlot(
"acceleration-graph",
[accelerationData],
accelerationLayout
);
const magnetometerPlot = Plotly.newPlot(
"magnetometer-graph",
[magnetometerData],
magnetometerLayout
);
var socket = io();
socket.on("connect", function () {
socket.emit("my event", { data: "I'm connected!" });
});
socket.on("acceleration", function (data) {
console.log('X_Accel: ' + accelerationData.x)
accelerationData.x.push(data.x);
accelerationData.y.push(data.y);
Plotly.update(accelerationPlot, [accelerationData], accelerationLayout);
});
socket.on("magnetometer", function (data) {
console.log('X_Mag: ' + magnetometerData.x)
magnetometerData.x.push(data.x);
magnetometerData.y.push(data.y);
Plotly.update(magnetometerPlot, [magnetometerData], magnetometerLayout);
});
</script>
</body>
</html>

Related

Using express-handlebars with Cytoscape.js

Hi I'm new to web development and I'm trying to play around with Cytoscape.js. I decided to use Node.js, Express, and Express-handlebars to run my webpage. I wanted to use Cytoscape.js to display a graph however I'm not sure how to use handlebars to get a reference to the container to initialize the cytoscape object.
Here's my main.handlebars file:
<!doctype html>
<html>
<head>
<title>Hello Cytoscape</title>
</head>
<body>
{{{body}}}
</body>
</html>
Here's my home.handlebars file:
<div id="cy"></div>
Here's my .js file:
/**
*
*/
'use strict';
var express = require('express');
var app = express();
var cytoscape = require('cytoscape');
//layout defaults to main, located in the views layout folder
var handlebars = require('express-handlebars').create({defaultLayout:'main'});
app.use(express.static('public'));
//sets the template engine to use for the express object
//a template engine will implement the view part of the app
app.engine('handlebars', handlebars.engine);
app.set('view engine', 'handlebars');
//initialize the cytoscape object
var cy = cytoscape({
//<----not sure how to do this----->
container: document.getElementById('cy'), // container to render in
elements: [ // list of graph elements to start with
{ // node a
data: { id: 'a' }
},
{ // node b
data: { id: 'b' }
},
{ // edge ab
data: { id: 'ab', source: 'a', target: 'b' }
}
],
style: [ // the stylesheet for the graph
{
selector: 'node',
style: {
'background-color': '#666',
'label': 'data(id)'
}
},
{
selector: 'edge',
style: {
'width': 3,
'line-color': '#ccc',
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle'
}
}
],
layout: {
name: 'grid',
rows: 1
},
// initial viewport state:
zoom: 1,
pan: { x: 0, y: 0 },
// interaction options:
minZoom: 1e-50,
maxZoom: 1e50,
zoomingEnabled: true,
userZoomingEnabled: true,
panningEnabled: true,
userPanningEnabled: true,
boxSelectionEnabled: false,
selectionType: 'single',
touchTapThreshold: 8,
desktopTapThreshold: 4,
autolock: false,
autoungrabify: false,
autounselectify: false,
// rendering options:
headless: false,
styleEnabled: true,
hideEdgesOnViewport: false,
hideLabelsOnViewport: false,
textureOnViewport: false,
motionBlur: false,
motionBlurOpacity: 0.2,
wheelSensitivity: 1,
pixelRatio: 'auto'
});
app.get('/', function (req, res) {
var context = {};
res.render('home', context);
});
//listener all for unrecognized urls
//return 404 not found response
app.use(function(req,res){
res.status(404);
res.render('404');
});
//listener for errors generate on server
//return 500 response
app.use(function(err, req, res, next){
console.error(err.stack);
res.type('plain/text');
res.status(500);
res.render('500');
});
if (module === require.main) {
// [START server]
// Start the server
var server = app.listen(process.env.PORT || 8080, function () {
var port = server.address().port;
console.log('App listening on port %s', port);
});
// [END server]
}
module.exports = app;
So I guess my question is how do I get a reference to the div container id="cy" to initialize my Cytoscape.js graph using express-handlebars, thanks in advance for any help.
If you run Cytoscape on the serverside -- as you're doing in your example -- then it's not running and not shown on the clientside.
Unless you're doing serverside-only graph analysis, you should be using Cytoscape on the clientside. Your page (main.handlebars) is the driver of everything clientside, so put your Cytoscape code there. Or in the page, reference your Cytoscape code with a <script> tag.

Get an error from Angular2 http in Es5

I am trying to use http with Angular2.
Here is my code:
var _domain = 'http://localhost:3000/';
app.Applications = ng.core.Injectable().Class({
constructor: [ng.http.Http, function(http) {
this.http = http;
this.emailExistUrl = _domain + 'api/applications/email';
}],
doesEmailExist: function(email) {
var data = { email: email };
return this.http.post(this.emailExistUrl, data)
.toPromise()
.then(function(response) { response.json().data; })
.catch(this.handleError);
}
});
The main component:
app.AppComponent = ng.core
.Component({
selector: 'register-form',
templateUrl: 'src/register/app.component.html',
providers: [app.Applications]
})
.Class({
constructor: [ng.core.ElementRef, app.Applications, function(ref, Applications) {
this.programs = JSON.parse(ref.nativeElement.getAttribute('programs'));
this.applications = Applications;
}],
doesEmailExist: function(email) {
return this.applications.doesEmailExist(email);
}
});
Here is main.js file:
document.addEventListener('DOMContentLoaded', function() {
ng.platformBrowserDynamic.bootstrap(app.AppComponent, [
ng.forms.disableDeprecatedForms(),
ng.forms.provideForms(),
ng.http.HTTP_PROVIDERS,
]);
});
When doesEmailExist is called I get an error from the http module:
vendor-client.min.js:55470 TypeError: Cannot read property 'platform_browser_private' of undefined
Any ideas?
FIXED:
Http was before platform-browser on the script tag list. :/
<script src="https://npmcdn.com/#angular/http/bundles/http.umd.js"></script>
<script src="https://npmcdn.com/#angular/platform-browser/bundles/platform-browser.umd.js"></script>
<script src="https://npmcdn.com/#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script>
The inverse is better :)
Try to assign http at the beginning of the constructor:
app.Applications = ng.core.Injectable().Class({
constructor: [ng.http.Http, function(http) {
this.http = http;
...
}],
doesEmailExist: function(email) {
...
}
});
EDIT
See this Plunker: http://plnkr.co/edit/aQWqxauklT7MqSjfhLFD. To simplify, I have put everything in main.js file, and instead of an http post I have implemented an http get. However, locally, even the http post works with a web service API. I hope it's helpful to solve your problem.

#ParseServer #OneSignal #ScheduledPush #ParseServerOneSignalPushAdapter

Issue Description
We are using OneSignal as 3rd party push service and configured it using parse-server-onesignal-push-adapter as we are sending pushes from cloud code. Normal pushes are working but scheduled pushes are not. No matter what we set to "push_time" parameter on Push.send(), pushes are sent immediately.
Expected Results
Working scheduled pushes
Actual Outcome
Pushes are sent immediately even if there is push_time parameter set on Parse.Push.send().
How we send pushes
Parse.Push.send({
where: query,
data: {
"alert": "Voting complete. Click here to see the results.",
"sound": "cheering.caf",
//"badge": "Increment",
"content-available": 1,
"category": "VOTING_COMPLETE",
"qc": request.object.id
},
push_time: pushTime
}, {
success: function() {
console.log('##### PUSH OK');
},
error: function(error) {
console.log('##### PUSH ERROR');
},
useMasterKey: true
});
Environment Setup
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');
var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var OneSignalPushAdapter = require('parse-server-onesignal-push-adapter');
var oneSignalPushAdapter = new OneSignalPushAdapter({
oneSignalAppId:"***************************",
oneSignalApiKey:"***************************"
});
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '',
fileKey: process.env.FILE_KEY || '******************************',
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse',
verifyUserEmails: true,
emailVerifyTokenValidityDuration: 2 * 60 * 60,
preventLoginWithUnverifiedEmail: true,
publicServerURL: 'http://***************************/parse',
enableAnonymousUsers: false,
revokeSessionOnPasswordReset: true,
appName: '************************',
emailAdapter: {
module: 'parse-server-simple-mailgun-adapter',
options: {
fromAddress: 'no-reply#***************************.com',
domain: 'mg.******************************.com',
apiKey: 'key-******************************',
}
},
oauth: {
twitter: {
consumer_key: "***************************",
consumer_secret: "***************************"
}
},
push: {
adapter: oneSignalPushAdapter
}
});
var app = express();
app.use('/public', express.static(path.join(__dirname, '/public')));
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
app.get('/', function(req, res) {
res.status(200).send('Make sure to star the parse-server repo on GitHub!');
});
app.get('/test', function(req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
ParseServer.createLiveQueryServer(httpServer);
the reason is because scheduling of push messages is not supported (yet) by parse server. Only parse.com currently supports it.
You can read about it in here
If you really need this feature i suggest you to try to schedule a job in cloud code that will do it for you. Since scheduling jobs is also not supported out of the box you can find temporary solution in here

Grunt jshint reporter to send out emails

I have added grunt jshint task to my grunt. I created custom reporter to send out jsHint output as email. My custom reporter function is invoked. But no emails are coming through. There are no errors in the code.
Grunt version: "grunt": "^0.4.5",
"nodemailer": "^1.11.0",
"nodemailer-sendmail-transport": "^1.0.0"
Here is the sample code:
var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
var async = require('async');
module.exports = {
reporter: function (errors) {
var len = errors.length,
str = '';
var items = [1];
errors.forEach(function (r) {
var file = r.file,
err = r.error;
str += file + ": line " + err.line + ", col " +
err.character + ", " + err.reason + "\n";
});
if (str) {
str += "\n" + len + " error" + ((len === 1) ? "" : "s") + "\n";
}
var transporter = nodemailer.createTransport( smtpTransport( {
service: "gmail",
secureConnection: false, // use SSL
port: 587, // port for secure SMTP
auth: {
user: "<my gmail username>",
pass: "<gmail account password>"
},
tls:{
ciphers:'SSLv3'
},
logger: true, // log to console
debug: true // include SMTP traffic in the logs
}));
// setup e-mail data with unicode symbols
var mailOptions = {
from: '<sender address>',
to: '<recipient address>',
subject: 'Hello', // Subject line
text: "why are you not working"
/* text: str */// plaintext body
/*html: '<b>Hello world</b>' // html body*/
};
async.eachSeries(items, function (item, next) {
transporter.sendMail(mailOptions, function(error, response){
// THIS CALLBACK IS NOT CALLED AT ALL
if(error){
console.log(error);
}else{
console.log("Message sent");
}
next(null);
});
}, function(err){
// All tasks are done now
console.log('All tasks are done now');
});
}
};
with async or without async doesn't matter. No emails are coming. I tried bye turning on the "Receive emails from unsecured apps" by following another stackoverflow post. That also did not help.
I would like to know is this correct approach or not? Any help/input is appreicated.

Atmosphere On message Throwing message multiple times on single push

Hi i am learning Atmosphere framework and new to it, please help me out to fix issue that when i am pushing message through
socket.push(atmosphere.util.stringifyJSON({author:"user1", message: "hello"}));
but on server side i could see ***{"author":"user1","message":"hello"}, 4 times for single push.
****clientside***
mode.controller('pingController',['$scope','atmosphereService','$cookies',function($scope,atmosphereService,$cookies){
$scope.model = {
transport: 'websocket',
messages: []
};
var socket;
user=angular.fromJson($cookies.get('user_details_object'))['user_name'];
pingUrl='/chat/'+user;
request = {
url:pingUrl ,
contentType: 'application/json',
logLevel: 'debug',
transport: 'websocket',
trackMessageLength: true,
reconnectInterval: 5000,
enableXDR: true,
timeout: 60000
};
request.onOpen = function(response){
$scope.model.transport = response.transport;
$scope.model.connected = true;
$scope.model.content = 'Atmosphere connected using ' + response.transport;
};
/*request.onClientTimeout = function(response){
$scope.model.content = 'Client closed the connection after a timeout. Reconnecting in ' + request.reconnectInterval;
$scope.model.connected = false;
socket.push(atmosphere.util.stringifyJSON({ author: "author", message: 'is inactive and closed the connection. Will reconnect in ' + request.reconnectInterval }));
setTimeout(function(){
socket = atmosphereService.subscribe(request);
}, request.reconnectInterval);
};*/
request.onReopen = function(response){
$scope.model.connected = true;
$scope.model.content = 'Atmosphere re-connected using ' + response.transport;
};
//For demonstration of how you can customize the fallbackTransport using the onTransportFailure function
request.onTransportFailure = function(errorMsg, request){
atmosphere.util.info(errorMsg);
request.fallbackTransport = 'websocket';
$scope.model.header = 'Atmosphere Chat. Default transport is WebSocket, fallback is ' + request.fallbackTransport;
};
request.onMessage = function(response){
var responseText = response.responseBody;
console.log("###########",responseText);
try{
//var message = atmosphere.util.parseJSON(responseText);
var message = atmosphere.util.parseJSON(responseText);
console.log("#$$$$$##",message);
var date = typeof(message.time) === 'string' ? parseInt(message.time) : message.time;
$scope.model.messages.push({author: message.ping});
}catch(e){
console.error("Error parsing JSON: ", responseText);
throw e;
}
};
/*request.onClose = function(response){
$scope.model.connected = false;
$scope.model.content = 'Server closed the connection after a timeout';
socket.push(atmosphere.util.stringifyJSON({ author: $scope.model.name, message: 'disconnecting' }));
};*/
request.onError = function(response){
$scope.model.content = "Sorry, but there's some problem with your socket or the server is down";
$scope.model.logged = false;
};
request.onReconnect = function(request, response){
$scope.model.content = 'Connection lost. Trying to reconnect ' + request.reconnectInterval;
$scope.model.connected = false;
};
socket = atmosphereService.subscribe(request);
$scope.ping=function(name){
console.log("=="+name);
request = {
url:'/chat/'+name ,
contentType: 'application/json',
logLevel: 'debug',
transport: 'websocket',
trackMessageLength: true,
reconnectInterval: 5000,
enableXDR: true,
timeout: 60000
};
socket.push(atmosphere.util.stringifyJSON({author:"user1", message: "hello"}));
}
}]);
****serverside****
package resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.Path;
import org.atmosphere.cache.UUIDBroadcasterCache;
import org.atmosphere.client.TrackMessageSizeInterceptor;
import org.atmosphere.config.service.AtmosphereHandlerService;
import org.atmosphere.cpr.AtmosphereFramework;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResponse;
import org.atmosphere.cpr.AtmosphereSession;
import org.atmosphere.handler.OnMessage;
import org.atmosphere.interceptor.AtmosphereResourceLifecycleInterceptor;
import org.atmosphere.interceptor.BroadcastOnPostAtmosphereInterceptor;
import org.atmosphere.interceptor.HeartbeatInterceptor;
#Path("/")
#AtmosphereHandlerService(path = "/chat/{user}",
broadcasterCache = UUIDBroadcasterCache.class,
interceptors = {AtmosphereResourceLifecycleInterceptor.class,
BroadcastOnPostAtmosphereInterceptor.class,
TrackMessageSizeInterceptor.class,
HeartbeatInterceptor.class
})
public class NotificationResource extends OnMessage<String>{
List<AtmosphereResource> resourceList= new ArrayList<AtmosphereResource>();
#Override
public void onMessage(AtmosphereResponse response, String message)
throws IOException {
System.out.println("***"+message);
}
}
output:
***{"author":"user1","message":"hello"}
***{"author":"user1","message":"hello"}
***{"author":"user1","message":"hello"}
***{"author":"user1","message":"hello"}
please help me out to fix this, i need one message, single click of push

Resources