File name
Commit message
Commit date
# MIT License
#
# Copyright (c) 2022 Kelvin Choi
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import dash
from dash.dependencies import Output, Input
from dash import dcc, html, dcc
from datetime import datetime
import json
import plotly.graph_objs as go
from collections import deque
from flask import Flask, request
server = Flask(__name__)
app = dash.Dash(__name__, server=server)
# CSV export and thats it.
MAX_DATA_POINTS = 1000
UPDATE_FREQ_MS = 100
time = deque(maxlen=MAX_DATA_POINTS)
accel_x = deque(maxlen=MAX_DATA_POINTS)
accel_y = deque(maxlen=MAX_DATA_POINTS)
accel_z = deque(maxlen=MAX_DATA_POINTS)
app.layout = html.Div(
[
dcc.Markdown(
children="""
# Live Sensor Readings
Streamed from Sensor Logger: tszheichoi.com/sensorlogger
"""
),
dcc.Graph(id="live_graph"),
dcc.Interval(id="counter", interval=UPDATE_FREQ_MS),
]
)
@app.callback(Output("live_graph", "figure"), Input("counter", "n_intervals"))
def update_graph(_counter):
data = [
go.Scatter(x=list(time), y=list(d), name=name)
for d, name in zip([accel_x, accel_y, accel_z], ["X", "Y", "Z"])
]
graph = {
"data": data,
"layout": go.Layout(
{
"xaxis": {"type": "date"},
"yaxis": {"title": "Acceleration ms<sup>-2</sup>"},
}
),
}
if (
len(time) > 0
): # cannot adjust plot ranges until there is at least one data point
graph["layout"]["xaxis"]["range"] = [min(time), max(time)]
graph["layout"]["yaxis"]["range"] = [
min(accel_x + accel_y + accel_z),
max(accel_x + accel_y + accel_z),
]
return graph
@server.route("/data", methods=["POST"])
def data(): # listens to the data streamed from the sensor logger
if str(request.method) == "POST":
print(f'received data: {request.data}')
data = json.loads(request.data)
for d in data['payload']:
if (
d.get("name", None) == "accelerometer"
): # modify to access different sensors
ts = datetime.fromtimestamp(d["time"] / 1000000000)
if len(time) == 0 or ts > time[-1]:
time.append(ts)
# modify the following based on which sensor is accessed, log the raw json for guidance
accel_x.append(d["values"]["x"])
accel_y.append(d["values"]["y"])
accel_z.append(d["values"]["z"])
return "success"
if __name__ == "__main__":
app.run_server(port=8000, host="0.0.0.0")