# 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-2"}, } ), } 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")