Raspberry Pi python website with plotly graph updates - python

I am currently working on a project from home where I have a network of Arduino's sending data (temp humidity etc.) to a raspberry pi. I want to make the rasp take the data and using plotly make a variety of graphs and then embed said graphs into a website that automatically updates at a set interval. I already have the network up and running I am just stuck on how to get the graphs on to a HTML page and have it update. I was considering just running a Python script that makes a webpage and re-write it with the new graphs every time. This seems highly inefficient so I was wondering if there was a better way of doing it?

Some time ago I had a very similar problem. A very simple solution was to use Python3's http.server to return a JSON with a time stamp and the temperature.
# !/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import random
import json
import time
def send_header(BaseHTTPRequestHandler):
BaseHTTPRequestHandler.send_response(200)
BaseHTTPRequestHandler.send_header('Access-Control-Allow-Origin', '*')
BaseHTTPRequestHandler.send_header('Content-type:', 'application/json')
BaseHTTPRequestHandler.end_headers()
class MyRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
# returns the temperature
if self.path == '/temperature':
send_header(self)
self.wfile.write(bytes(json.dumps({'time': time.strftime('%H:%M:%S', time.gmtime()), 'temperature': random.randint(0, 100)}), 'utf-8'))
if __name__ == '__main__':
# start server
server = HTTPServer(('', 8099), MyRequestHandler)
server.serve_forever()
The data is then received via simple vanilla JavaScript and put into plotly. Every 1000 ms a request is sent to the server and the graph is updated accordingly.
<html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script>
var temperatures;
var temperatures_x = [];
var temperatures_y = [];
var server_url = "";
//basic request handler
function createRequest() {
var result = null;
if (window.XMLHttpRequest) {
// FireFox, Safari, etc.
result = new XMLHttpRequest();
if (typeof result.overrideMimeType != "undefined") {
result.overrideMimeType("text/xml"); // Or anything else
}
} else if (window.ActiveXObject) {
// MSIE
result = new ActiveXObject("Microsoft.XMLHTTP");
}
return result;
}
//gets the temperature from the Python3 server
function update_temperatures() {
var req = createRequest();
req.onreadystatechange = function () {
if (req.readyState !== 4) {
return;
}
temperatures = JSON.parse(req.responseText);
return;
};
req.open("GET", server_url + "/temperature", true);
req.send();
return;
}
//updates the graph
function update_graph() {
update_temperatures();
temperatures_x.push(temperatures.time)
temperatures_y.push(temperatures.temperature)
Plotly.newPlot('graph_t', [{x: temperatures_x, y: temperatures_y}]);
}
//initializes everything
window.onload = function () {
document.getElementById("url").onchange = function () {
server_url = document.getElementById("url").value;
};
server_url = document.getElementById("url").value;
//timer for updating the functions
var t_cpu = setInterval(update_graph, 1000);
};
</script>
</head>
<body>
<li>
URL and port<input type="text" id="url" value="http://localhost:8099">
</li>
<div class="plotly_graph" id="graph_t"></div>
</body>
</html>

Related

HttpResponseMessage returns 403 in .NET

I have a async method which make a HttpClient call repeatedly in .Net. I simulate my code as a small console app below:
private static HttpClient req { get; set; } = new HttpClient();
static async Task Main(string[] args)
{
Console.WriteLine("Please press enter to start healthCheck");
Console.ReadLine();
healthCheck();
Console.ReadLine();
}
private static async Task healthCheck()
{
while (true)
{
req.DefaultRequestHeaders.Add("apikey", "myPassword");
string strUrl = "http://myUrl";
HttpResponseMessage hrm = await req.GetAsync(strUrl);
Console.WriteLine("=> statusCode:" + (int)hrm.StatusCode);
await Task.Delay(5000);
}
}
The output is:
The problem is when I use Postman or write this code with python as below, every time it responded 200 instead of 403.
import requests as req
import time as t
url = "http://adpsms.adpdigital.com/report/?date=2021-08-30"
customHeader = {"apikey": "sssrjdIiGisbViKA"}
i = 10
while (i > 0):
response = req.get(url, headers = customHeader)
print("statusCode: " + str(response.status_code))
i -= 1
t.sleep(5)
I supposed it is a server error but when I responded 200 every time with python I understand it would be a problem with my code or something client based.
Since my project is based on .NET I want to make it work on it.
Any suggestion would be appreciated.
On every iteration of your loop, you are adding DefaultRequestHeaders.
It means that they will be added again and again on each iteration of your cycle to the global instance of HttpClient
According to the official docs these headers will be sent with each request.
For your particular task you might add them only once(that's why the name contains prefix default.)
So if you slightly rewrite your code like this:
private static HttpClient req { get; set; } = new HttpClient();
static async Task Main(string[] args)
{
Console.WriteLine("Please press enter to start healthCheck");
Console.ReadLine();
AddDefaultHeaders();
healthCheck();
Console.ReadLine();
}
private static void AddDefaultHeaders()
{
req.DefaultRequestHeaders.Add("apiKey", "myPassword");
}
private static async Task healthCheck()
{
while (true)
{
string strUrl = "http://myUrl";
HttpResponseMessage hrm = await req.GetAsync(strUrl);
Console.WriteLine("=> statusCode:" + (int)hrm.StatusCode);
await Task.Delay(5000);
}
}
It should works fine.

Real time notifications with Django and Socket.io

currently i'm implementing real time notifications for my Django project.
I'm following instructions from this tutorial. Problem is, i'm using Socket.io 1.4.5 and tutorial is written for pre-1.0 versions. So i had to adapt some code following 'Migrating from 0.9' guideline on Socket.io site. What i got is:
var http = require('http');
var server = http.createServer().listen(8002);
var io = require('socket.io')(server);
var cookie_reader = require('cookie');
var querystring = require('querystring');
var redis = require('redis');
// Supposedly this should store cookie set by Django
io.use(function(socket,accept){
var data = socket.request;
if(data.headers.cookie){
data.cookie = cookie_reader.parse(data.headers.cookie);
return accept(null, true);
}
return accept('error', false);
});
io.sockets.on('connection', function (socket) {
// Redis client
client = redis.createClient();
// Subscribe to notification channel
client.subscribe('notifications.' + socket.handshake.cookie['sessionid']);
console.log('subscribed');
//Grab message from Redis and send to client
client.on('message', function(channel, message){
console.log('on message', message);
socket.send(message);
});
// Unsubscribe
socket.on('disconnect', function() {
client.unsubscribe('notifications.' + socket.handshake.cookie['sessionid']);
});
});
When i'm running this script:
node notifications.js
After 2 seconds of silence i get this error:
client.subscribe('notifications.' + socket.handshake.cookie['sessionid']);
^
TypeError: Cannot read property 'sessionid' of undefined
at Namespace.<anonymous> (path/to/notifications.js)
at Namespace.emit (events.js:107:17)
at Namespace.emit (/path/to/node_modules/socket.io/lib/namespace.js:206:10)
at /path/to/node_modules/socket.io/lib/namespace.js:174:14
at process._tickCallback (node.js:355:11)
Can somebody point me to what i did wrong?
Just found what my mistake was.
To access cookie, instead of socket.handshake i should be using socket.request. So my current code looks like this now:
var http = require('http');
var server = http.createServer().listen(8002);
var io = require('socket.io')(server);
var cookie_reader = require('cookie');
var querystring = require('querystring');
var redis = require('redis');
io.use(function(socket,accept){
var data = socket.request;
if(data.headers.cookie){
data.cookie = cookie_reader.parse(data.headers.cookie);
return accept(null, true);
}
return accept('error', false);
});
io.on('connection', function (socket) {
// Redis client
client = redis.createClient();
// Subscribe to notification channel
client.subscribe('notifications.' + socket.request.cookie['sessionid']);
console.log('subscribed');
//Grab message from Redis and send to client
client.on('message', function(channel, message){
console.log('on message', message);
socket.send(message);
});
// Unsubscribe
socket.on('disconnect', function() {
client.unsubscribe('notifications.' + socket.request.cookie['sessionid']);
});
});

Emitting messages from python-shell to a browser in a Node Express App

I have an express app and I would like to be able to trigger python scripts via routes and emit the log into the browser.
I have created a route which triggers the python scripts correctly and outputs the log into the node console using python-shell module. How can I push this log to the browser in real time.
I have a button on an index.html page which triggers an Ajax post request to a /python route below. I have tried to implement this with socket.io but haven't managed to get my head around it. Is socket.io the way forward, please point me in the right direction or can someone recommend an alternative?
My file layout is:
server.js
var express = require('express');
var path = require('path');
var app = express();
var port = process.env.PORT || 3000;
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
/* A bit inbetween */
server.listen(port)
app/routes.js
var PythonShell = require('python-shell');
var config = require('../config/config');
module.exports = function(app) {
app.get('/', function(req, res) {
res.render('pages/index.ejs', {
pageTitle: 'Index'
}); // load the index.ejs file
});
app.post('/test', function(req, res) {
var options = {
mode: 'text',
pythonPath: config.pythonPath,
pythonOptions: ['-u'],
scriptPath: config.pythonScriptsDirectory
};
var pyshell = new PythonShell('printRange.py', options);
pyshell.on('message', function (message) {
console.log(message);
});
res.sendStatus(200)
});
}
Thanks in advance
socket.io is a good solution. This will take care of passing the messages from the server to the client. You just post the message to on the server side, and have a callback react to it on the client side
On the server side you'll have something like this:
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(){
console.log('connected');
});
server.listen(3000);
...
var pyshell = new PythonShell('printRange.py', options);
pyshell.on('message', function (message) {
if (connected)
io.emit('logentry',message);
});
On the client side, you'll have something like this:
<script src='/socket.io/socket.io.js'></script>
<script>
var socket = io();
socket.on('logentry',function(log_entry){
add_to_html(log_entry); // You need to implement this function.
});
</script>

Uploading a file in ajax to CherryPy

I am trying to upload many files at once to my CherryPy server.
I am following this tutorial that shows PHP code on the server side.
The JavaScript part is simple. Here is a summary of what it does:
function FileSelectHandler(e) {
var files = e.target.files || e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "upload", true);
xhr.setRequestHeader("X_FILENAME", file.name);
xhr.send(file);
}
I translated the upload.php described in the tutorial into something like this:
def upload(self):
[...]
When the server receives the request I can see that cherrypy.request.headers['Content-Length'] == 5676
which is the length of the file I'm trying to upload, so I assume the whole file has been sent to the server.
How do I get the content of the file?
At its minimum it looks like the following. Tested in Firefox and Chromium. If you need to support legacy browsers I'd look at some JavaScript library for polyfills and fallback.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import shutil
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
}
}
class App:
#cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<head>
<title>CherryPy Async Upload</title>
</head>
<body>
<form id='upload' action=''>
<label for='fileselect'>Files to upload:</label>
<input type='file' id='fileselect' multiple='multiple' />
</form>
<script type='text/javascript'>
function upload(file)
{
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(event)
{
console.log('progess', file.name, event.loaded, event.total);
});
xhr.addEventListener('readystatechange', function(event)
{
console.log(
'ready state',
file.name,
xhr.readyState,
xhr.readyState == 4 && xhr.status
);
});
xhr.open('POST', '/upload', true);
xhr.setRequestHeader('X-Filename', file.name);
console.log('sending', file.name, file);
xhr.send(file);
}
var select = document.getElementById('fileselect');
var form = document.getElementById('upload')
select.addEventListener('change', function(event)
{
for(var i = 0; i < event.target.files.length; i += 1)
{
upload(event.target.files[i]);
}
form.reset();
});
</script>
</body>
</html>
'''
#cherrypy.expose
def upload(self):
'''Handle non-multipart upload'''
filename = os.path.basename(cherrypy.request.headers['x-filename'])
destination = os.path.join('/home/user', filename)
with open(destination, 'wb') as f:
shutil.copyfileobj(cherrypy.request.body, f)
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)

Using websockets in telnet server in Python3

I have been working on a game server written in python3. My goal is to keep the communication options on it very open so that multiple different clients can easily connect. Currently all communication has been through telnet using miniboa. I would like to have the option to allow for web based clients as well. It seems like the easiest option for that would be to allow websocket connections. I have been playing around with websockify which works, however I would prefer to not use a proxy if possible because then all the connections appear to come from the proxy. Ideally what I would like is something that I can put into my telnet server to recognize a websocket handshake request (as compared to the regular requests), return the proper handshake, then keep the connection going so the commands being sent/recieved through telnet and websockets are the same. I haven't been able to find anything that allows me to do this automatically so I have been experimenting around with writing my own code to recognize a websocket handshake and reply with a corresponding handshake. I have looked at many other posts and examples, epecially python websocket handshake (RFC 6455) which I modified and converted to the following test program
#!/usr/bin/env python3
from miniboa import TelnetServer
from base64 import b64encode
from hashlib import sha1
clientlist = []
def client_connects(client):
clientlist.append(client)
def client_disconnects(client):
clientlist.remove(client)
def process_clients():
for client in clientlist:
if client.active and client.cmd_ready:
total_cmd = client.get_command()
print("incoming = {}" .format(total_cmd))
if total_cmd.find(" ") != -1: # breaking apart incoming command
cmd, cmd_var = total_cmd.split(" ", 1)
else:
cmd = total_cmd
cmd_var = ""
if cmd == "Sec-WebSocket-Key:":
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
cmd_var = cmd_var + GUID
encoded = cmd_var.encode('utf-8')
response_key = b64encode(sha1(encoded).digest())
websocket_answer = (
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
'Sec-WebSocket-Accept: {key}\r\n\r\n',
)
handshake = '\r\n'.join(websocket_answer).format(key=response_key)
client.handshakestr = handshake
if cmd == "Upgrade:":
print("Sending handshake:")
print(client.handshakestr)
print("End of Handshake")
client.send(client.handshakestr)
server = TelnetServer(port=6112, on_connect=client_connects, on_disconnect=client_disconnects)
while True:
process_clients()
server.poll()
which seems to get me past the initial handshake but then it immediately drops. From the output it looks like the browser is expecting something further but I can't figure out what. For a client I am using the following code on firefox 29.0 I downloaded from http://opiate.github.io/SimpleWebSocketServer/
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">
function init()
{
document.myform.url.value = "ws://localhost:8000/"
document.myform.inputtext.value = "Hello World!"
document.myform.disconnectButton.disabled = true;
}
function doConnect()
{
websocket = new WebSocket(document.myform.url.value);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}
function onOpen(evt)
{
writeToScreen("connected\n");
document.myform.connectButton.disabled = true;
document.myform.disconnectButton.disabled = false;
}
function onClose(evt)
{
writeToScreen("disconnected\n");
document.myform.connectButton.disabled = false;
document.myform.disconnectButton.disabled = true;
}
function onMessage(evt)
{
writeToScreen("response: " + evt.data + '\n');
}
function onError(evt)
{
writeToScreen('error: ' + evt.data + '\n');
websocket.close();
document.myform.connectButton.disabled = false;
document.myform.disconnectButton.disabled = true;
}
function doSend(message)
{
writeToScreen("sent: " + message + '\n');
websocket.send(message);
}
function writeToScreen(message)
{
document.myform.outputtext.value += message
document.myform.outputtext.scrollTop = document.myform.outputtext.scrollHeight;
}
window.addEventListener("load", init, false);
function sendText() {
doSend( document.myform.inputtext.value );
}
function clearText() {
document.myform.outputtext.value = "";
}
function doDisconnect() {
websocket.close();
}
</script>
<div id="output"></div>
<form name="myform">
<p>
<textarea name="outputtext" rows="20" cols="50"></textarea>
</p>
<p>
<textarea name="inputtext" cols="50"></textarea>
</p>
<p>
<textarea name="url" cols="50"></textarea>
</p>
<p>
<input type="button" name=sendButton value="Send" onClick="sendText();">
<input type="button" name=clearButton value="Clear" onClick="clearText();">
<input type="button" name=disconnectButton value="Disconnect" onClick="doDisconnect();">
<input type="button" name=connectButton value="Connect" onClick="doConnect();">
</p>
</form>
</html>
So does anyone know either:
1. an easier way to use websockets with my telnet server?
2. what is wrong with my attempts at responding to a websocket connection?
3. if I should give up and settle for using a proxy with web connections?
Tornado has a nice compliant WebSocket handler. You can use that, or use it for reference when building yours.

Categories

Resources