├── .gitattributes
├── .gitignore
├── DockerFile
├── LICENSE
├── README.md
├── config.ini
├── config_handler.py
├── data_stream.py
├── data_streams
└── samples.py
├── examples
├── VisClient.py
├── send_and_setup_rtsp_server_address_using_FFMPEG_or_GSTREAMER.py
├── send_geomarkers.py
├── send_heatmap_data.py
├── send_heatmap_data_as_image.py
├── send_post_request_to_HTTP_server.py
├── send_random_number_stream.py
├── send_stock_price_stream.py
├── send_text_stream.py
└── send_webcam_images.py
├── flask_handler.py
├── http_client.py
├── http_server.py
├── image_server.py
├── images
├── chartjs.png
├── demo1.PNG
├── demo1.gif
├── demo2.gif
├── flask_logo.png
├── jquery.jpg
├── plotly.png
├── python.png
└── structure.png
├── main.py
├── requirements.txt
├── scheduler.py
├── socket_client.py
├── socket_server.py
├── static
└── css
│ └── style.css
└── templates
├── camera_sample.html
├── index.html
└── map_sample.html
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | .hypothesis/
51 | .pytest_cache/
52 |
53 | # Translations
54 | *.mo
55 | *.pot
56 |
57 | # Django stuff:
58 | *.log
59 | local_settings.py
60 | db.sqlite3
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | target/
74 |
75 | # Jupyter Notebook
76 | .ipynb_checkpoints
77 |
78 | # IPython
79 | profile_default/
80 | ipython_config.py
81 |
82 | # pyenv
83 | .python-version
84 |
85 | # pipenv
86 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
87 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
88 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
89 | # install all needed dependencies.
90 | #Pipfile.lock
91 |
92 | # celery beat schedule file
93 | celerybeat-schedule
94 |
95 | # SageMath parsed files
96 | *.sage.py
97 |
98 | # Environments
99 | .env
100 | .venv
101 | env/
102 | venv/
103 | ENV/
104 | env.bak/
105 | venv.bak/
106 |
107 | # Spyder project settings
108 | .spyderproject
109 | .spyproject
110 |
111 | # Rope project settings
112 | .ropeproject
113 |
114 | # mkdocs documentation
115 | /site
116 |
117 | # mypy
118 | .mypy_cache/
119 | .dmypy.json
120 | dmypy.json
121 |
122 | # Pyre type checker
123 | .pyre/
124 |
--------------------------------------------------------------------------------
/DockerFile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:18.04
2 |
3 | RUN apt-get update
4 | RUN apt-get install -y python3 python3-dev python3-pip
5 | RUN apt-get install -y libsm6 libxext6 libxrender-dev
6 |
7 | COPY ./ ./app
8 | WORKDIR /app
9 |
10 | # Make sure to expose all ports
11 | EXPOSE 80 8001 8002 8003
12 |
13 | RUN pip3 install -r requirements.txt
14 |
15 | CMD python3 main.py
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019 Grebtsew
2 |
3 | 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:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | 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.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Automatic Visualization of Realtime Data Stream Charts in Flask
2 | Visualize arbitrary realtime data streams with just a few lines of code!
3 |
4 | 
5 |
6 |
7 | Table of Contents (click to expand)
8 |
9 |
10 |
11 | - [About](#About)
12 | - [Solution](#Solution)
13 | - [Getting-Started](#Getting-Started)
14 | - [How-to-Send-data-to-your-Server](#How-to-Send-data-to-your-Server)
15 | - [Docker](#Docker)
16 | - [Demo](#demo)
17 | - [Examples](#examples)
18 | - [What-is-flask?](#What-is-flask?)
19 | - [What-is-JSChart?](#What-is-Chart.JS?)
20 | - [License](#license)
21 | - [Sources](#sources)
22 |
23 |
24 |
25 |
26 | # About
27 | Visualizing data flows are important in a project where maintaining data streams are of priority.
28 | The abiliy to visualize data in realtime can contribute with huge advantages while debugging code or demonstrating. In this implementation we are visualizing data in charts using Chart.JS, a simple powerful library for creating charts in Javascript. The server can now also visualize image streams and heatmaps using Plotly, a modern analytics app for enterprises. This implementation utilizes Flask and is developed mainly in python3 and Javascript.
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | ## Solution
41 | This implementation is started by running the `main.py` file. The `Starter` will then set a timer for triggering the webbrowser after one second and then start the `Flask Handler`. The `Flask Handler` will start the website containing a `Flask-SocketIO` server. The `Flask-Server` will receive json objects and update the `GUI` listview. When the `Flask-Server` is started the `Scheduler` will be triggered. The `Scheduler` will start the middle-man servers consisting of a `TCP Socket Server`, a `TCP Socket Server for large files` and a `HTTP Server` which has the purpose of receiving messages and proxy them to the flask server. In the `demo` we also start some data streams with the scheduler. You basicly have two alternatives on sending data to this implementation. Either create a data stream in the `scheduler` or create a seperate `tcp socket client` or `http client` and send data to the tcp socket server while running. See examples.
42 |
43 | See program structure image below:
44 | 
45 |
46 | # Getting Started
47 | 1. Install program by firstly installing all the required packages in python3:
48 | **Note**: If you want to use docker see [here](#Docker).
49 | ```
50 | pip install -r requirements.txt
51 | ```
52 |
53 | 2. Start the implementation by running:
54 | ```
55 | python3 main.py
56 | ```
57 |
58 | 3. If the website doesn't open automatically, open a webbrowser of your choice and go to: `https://127.0.0.1:5000/`
59 |
60 | 4. Edit the `Scheduler` file and Comment the `demo()` line, to make sure the demo data streams won't start.
61 |
62 | 5. Create your stream by looking at the [heading below](#How-to-Send-data-to-your-Server).
63 |
64 | Example data json:
65 | ```
66 | data = {
67 | "id":1337,
68 | "value": [1,1],
69 | "type":"line",
70 | "active_points": 20,
71 | "label":"Label",
72 | "legend": ["one", "two"],
73 | "name":"Example",
74 | "borderColor":["#3e95cd", "#e8c3b9"],
75 | "backgroundColor":["#3e95cd","#e8c3b9"],
76 | "api_crypt":"password-1"
77 | }
78 | ```
79 |
80 | # Change Config
81 | Ports and addresses can be changed in the `config.ini` file.
82 |
83 | # How to Send data to your Server
84 | As mentioned in the [solution heading above](#Solution) there are two ways of sending data streams to this implementation, creating a socket client or creating data stream in the implementation.
85 |
86 | ## Create a seperate TCP Socket Client
87 | I created two simple example of tcp socket clients in `examples/`. One that creates a data stream from live stock share prices and one that create a data stream from random numbers.
88 |
89 | ## Using the scheduler
90 | Take a closer look at the `scheduler.py` file, where more functions can be added to server start. In the current implementation there are two stream examples using scheduler in the `demo()` function.
91 |
92 | The first one is a seperate tcp socket client started from the scheduler. Check out the scheduler and `socket_client.py`. The second one is a stream using the `DataStream` class. Check out `data_streams/samples.py`.
93 |
94 | ## Showing RTSP Streams
95 | To create a video feed send a json with rtsp address as value and a unique id. Example:
96 | ```
97 | video_data= {
98 | 'id': 12,
99 | 'value': rtsp://192.168.0.25:554/live.sdp,
100 | 'type': 'video_stream',
101 | 'name': 'Video Stream HTTP Example',
102 | # Crypt password from config.ini
103 | 'api_crypt':CRYPT
104 | }
105 | ```
106 |
107 | # Docker
108 | 1. Build the docker image for this project by running:
109 | ```
110 | docker build . --tag="JSChart-flask:1.0"
111 | ```
112 | 2. Run the image in background by running:
113 | ```
114 | docker run -d -p 80:80 JSChart-flask:1.0
115 | ```
116 |
117 | 2. Or Run image in interactive mode by running:
118 | ```
119 | docker run -it -p 80:80 JSChart-flask:1.0
120 | ```
121 |
122 | 3. Open your webbrowser of choice and go to:
123 | ```
124 | http://127.0.0.1/
125 | or
126 | http://localhost/
127 | ```
128 | **Note**: all ports and addresses can be changed in `config.ini`
129 | # Demo
130 |
131 | This is the output on the console during execution.
132 | 
133 |
134 | This is how the implementation looks like during execution of the `demo()`.
135 | 
136 |
137 | Examples of how each chart look and how the data should be represented in json see:
138 | * https://www.chartjs.org/samples/latest/
139 | * https://tobiasahlin.com/blog/chartjs-charts-to-get-you-started
140 |
141 | ## What is flask?
142 | [Flask](https://en.wikipedia.org/wiki/Flask_(web_framework)) is a micro web framework, enabling websites to be hosted in python.
143 |
144 | ## What is Chart.JS?
145 | [Chart.JS](https://www.chartjs.org/) is an opensource project with the main purpose to provide awesome charts for html5 and javascript.
146 |
147 | ## What is Plotly?
148 | [Plotly](https://plot.ly/) is a collection of open source Graphing Libraries for visualizing data in a vast amount of formats.
149 |
150 | # Licenses
151 | See 
152 |
153 | # Known Issues
154 | List of known issues:
155 | * Ignore the `WebSocket transport not available. Install eventlet or gevent and gevent-websocket for improved performance.` warning as eventlet doesn't support Flask-socketio! Make sure eventlet is not installed in your python environment!
156 |
157 | # Sources
158 | The main inspiration and solutions comes from the following sources:
159 | * https://gitlab.com/patkennedy79/flask_chartjs_example
160 | * https://github.com/roniemartinez/real-time-charts-with-flask
161 |
162 | # Deprecated Demo
163 | A deprecated demo can be intresting to see how the application has developed from earlier versions!
164 | 
165 |
166 |
167 | # TODO
168 | These are functions that I will add
169 | * geo tagging free api map
170 | * 3d graphs
171 | * 3d algoritm
172 | * Bubble matrix
173 | * Tree
174 |
--------------------------------------------------------------------------------
/config.ini:
--------------------------------------------------------------------------------
1 | [Flask]
2 | # HOST will give error if not this
3 | HOST=0.0.0.0
4 | # PORT must be same as website port
5 | PORT=80
6 |
7 | [Website]
8 | HOST=127.0.0.1
9 | # PORT must be same as Flask Port
10 | PORT=80
11 |
12 | [SocketServer]
13 | HOST=127.0.0.1
14 | PORT=8010
15 |
16 | [ImageServer]
17 | HOST=127.0.0.1
18 | PORT=8020
19 |
20 | [HTTPServer]
21 | HOST=127.0.0.1
22 | PORT=8030
23 | CRYPT-PASSWORD=password-1
24 |
--------------------------------------------------------------------------------
/config_handler.py:
--------------------------------------------------------------------------------
1 | import configparser
2 |
3 | class ConfigHandler():
4 |
5 | def __init__(self, path="config.ini"):
6 | self.path = path
7 | self.config = self.readconfig_file()
8 |
9 | def readconfig_file(self):
10 | config = configparser.ConfigParser()
11 | config.read("config.ini")
12 | return config
13 |
14 | def __str__(self):
15 | print("List all contents")
16 | for section in self.config.sections():
17 | print("Section: %s" % section)
18 | for options in self.config.options(section):
19 | print("x %s:::%s:::%s" % (options,
20 | self.config.get(section, options),
21 | str(type(options))))
22 | def get_all(self, section):
23 | res = []
24 | for options in self.config.options(section):
25 | res.append(self.config.get(section, options))
26 |
27 | return res
28 |
29 | def get(self, section, value):
30 | return self.config.get(section, value)
31 | def getboolean(self, section, value):
32 | return self.config.getboolean(section,value)
33 |
--------------------------------------------------------------------------------
/data_stream.py:
--------------------------------------------------------------------------------
1 | from threading import Thread
2 | import flask_handler
3 | from datetime import datetime
4 | import time
5 | import threading
6 | """
7 | This file contains some data structures for better implementation structure.
8 | """
9 |
10 | class Config():
11 | # Describes the visuals of graphs
12 | def __init__(self, _id= 0, _type = 'line', _active_points = 20,
13 | _delay = 1, _name = "RealtimeGraph", _label=["Value"], _legend=["data"],
14 | _width = 200, _height = 100, backgroundColor = ["rgb(255, 99, 132)"],
15 | borderColor = ["rgb(255, 99, 132)"], fill = "false"):
16 | self.type = _type
17 | self.active_points = _active_points
18 | self.delay = _delay = 1
19 | self.id = _id
20 | self.name = _name
21 | self.label = _label
22 | self.legend = _legend
23 | self.width = _width
24 | self.height = _height
25 | self.backgroundColor = backgroundColor
26 | self.borderColor = borderColor
27 | self.fill = fill
28 |
29 | class DataStream(Thread):
30 | def __init__(self, _config, _data_func):
31 | super(DataStream, self).__init__()
32 | self.data_func = _data_func
33 | self.config = _config
34 |
35 | def run(self):
36 | while not flask_handler.thread_stop_event.isSet():
37 | flask_handler.socketio.emit('server',
38 | {'id':self.config.id,
39 | 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
40 | 'value': self.data_func(),
41 | 'type': self.config.type,
42 | 'active_points': self.config.active_points,
43 | 'label': self.config.label,
44 | 'legend': self.config.legend,
45 | 'name': self.config.name,
46 | 'width': self.config.width,
47 | 'height': self.config.height,
48 | "backgroundColor": self.config.backgroundColor,
49 | "borderColor" : self.config.borderColor,
50 | "fill" : self.config.fill},
51 | namespace='/test')
52 | time.sleep(self.config.delay)
53 |
54 |
55 | def def_param(vari, deff):
56 | if vari is None:
57 | return deff
58 | else:
59 | return vari
60 |
61 | def send_request(id, data, type = 'line', active_points = 20, _label="Value", _legend="data", _width = 200, _height = 100, _name = "Graph", backgroundColor = "rgb(255, 99, 132)", borderColor = "rgb(255, 99, 132)", fill = "false"):
62 | type = def_param(type, 'line')
63 | active_points = def_param(active_points, 20)
64 | _label = def_param(_label, ['Value'])
65 | _legend = def_param(_legend, ['data'])
66 | _height = def_param(_height, 200)
67 | _width = def_param(_width, 100)
68 | _name = def_param(_name, 'Graph')
69 | fill = def_param(fill, "False")
70 | backgroundColor = def_param(backgroundColor, ["rgb(255, 99, 132)"])
71 | borderColor = def_param(borderColor, ["rgb(255, 99, 132)"])
72 |
73 | flask_handler.socketio.emit('server',
74 | {'id': id,
75 | 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
76 | 'value': data,
77 | 'type': type,
78 | 'active_points': active_points,
79 | 'label': _label,
80 | 'legend': _legend,
81 | 'name': _name,
82 | 'width': _width,
83 | 'height': _height,
84 | "backgroundColor": backgroundColor,
85 | "borderColor" : borderColor,
86 | "fill" : fill},
87 | namespace='/test')
88 |
--------------------------------------------------------------------------------
/data_streams/samples.py:
--------------------------------------------------------------------------------
1 | # Example random_nr data stream
2 | from data_stream import Config
3 | from random import random
4 | from random import randrange
5 |
6 | """
7 | Random generator working on this pc
8 | """
9 | def random_nr():
10 | return [round(random()*10, 3)]
11 |
12 | random_nr_config = Config(_name = "Random Number Stream")
13 |
14 | """
15 | These are sample requests send via tcp sockets
16 | """
17 |
18 | def random_color():
19 | color = [randrange(255),randrange(255),randrange(255)]
20 | return color
21 |
22 | samplelist = []
23 |
24 | samplelist.append('{"id":10, "value": ['+str(int(round(random()*10, 3)))+'], "type":"line","active_points": 20, "width":300, "height":150, "label":["value"], "legend":["legend"], "name":"line chart" }')
25 | samplelist.append('{"id":20, "value": ['+str(round(random()*10, 3))+'], "type":"line","active_points": 20, "width":300, "height":150, "label":["value"], "legend":["legend"], "name":"line chart with full json", "fill": true, "backgroundColor":["#3e95cd"], "borderColor":["#3e95cd"]}')
26 | samplelist.append('{"id":40, "value": ['+str(round(random()*10, 3))+'], "type":"pie","active_points": 20, "width":300, "height":150, "label":["value"], "legend":["legend"], "name":"Pie chart", "fill": false, "backgroundColor":["#e8c3b9"], "borderColor":["#c45850"]}')
27 | samplelist.append('{"id":30, "value": ['+str(round(random()*10, 3))+'], "type":"bar","active_points": 20, "width":300, "height":150, "label":["value"], "legend":["legend"], "name":"Bar chart", "fill": false, "backgroundColor":["#8e5ea2"], "borderColor":["#e8c3b9"]}')
28 | samplelist.append('{"id":50, "value": ['+str(round(random()*10, 3))+'], "type":"radar","active_points": 20, "width":300, "height":150, "label":["value"], "legend":["legend"], "name":"Radar chart", "fill": false, "backgroundColor":["#8e5ea2"], "borderColor":["#c45850"]}')
29 | samplelist.append('{"id":70, "value": ['+str(round(random()*10, 3))+'], "type":"doughnut","active_points": 20, "width":300, "height":150, "label":["value"], "legend":["legend"], "name":"Doughnut chart", "fill": false, "backgroundColor":["#3e95cd"], "borderColor":["#c45850"]}')
30 | samplelist.append('{"id":80, "value": ['+str(round(random()*10, 3))+'], "type":"horizontalBar","active_points": 20, "width":300, "height":150, "label":["value"], "legend":["legend"], "name":"Horizontal Bar chart", "fill": false, "backgroundColor":["#3cba9f"], "borderColor":["#c45850"]}')
31 | #samplelist.append('{"id":60, "value": ['+str(int(round(random()*10, 3)))+'], "type":"polarArea","active_points": 20, "width":300, "height":150, "label":["value"], "legend":["legend"], "name":"Polar Area chart", "fill": false, "backgroundColor":["#3cba9f"], "borderColor":["#c45850"]}')
32 |
--------------------------------------------------------------------------------
/examples/VisClient.py:
--------------------------------------------------------------------------------
1 | """
2 | This Class uses the flask visualization repo to show data
3 | """
4 | import threading
5 | import socket
6 | import struct
7 | import pickle
8 | import cv2
9 |
10 | class VisClient(threading.Thread):
11 | """
12 | This client sends images for detection server
13 | """
14 |
15 | def __init__(self, address,port):
16 | super(VisClient,self).__init__()
17 | self.address = address
18 | self.port = port
19 | self.s = socket.socket()
20 | self.s.connect((self.address,self.port))
21 | self.encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
22 |
23 |
24 | def send_large(self,frame):
25 |
26 | data = pickle.dumps(frame, 0)
27 | size = len(data)
28 | #print("Sending Image of size ", size)
29 | self.s.sendall(struct.pack(">L", size) + data)
30 |
31 | def send(self, data):
32 | """
33 | Send data to vis
34 | """
35 | self.s.sendall(str.encode(data))
36 |
37 | def run(self):
38 | self.send()
39 |
--------------------------------------------------------------------------------
/examples/send_and_setup_rtsp_server_address_using_FFMPEG_or_GSTREAMER.py:
--------------------------------------------------------------------------------
1 | """
2 | This Demo demonstrates how to start a FFMPEG & GSTREAMER rtsp server of the webcam stream and send the address to
3 | our Visualizer for visualization!
4 | """
5 |
6 | address = "127.0.0.1"
7 | port = 1337
8 | webcam_name= "USB2.0 UVC 1M WebCam"
9 | Use_FFMPEG= False
10 |
11 | import os
12 |
13 | print ("Starting server")
14 |
15 | if Use_FFMPEG:
16 | # Create rtsp server for FFMPEG, require FFMPEG command installed on pc and a webcam!
17 | stream = os.popen('ffmpeg -f dshow -i video="'+webcam_name+'" -acodec libmp3lame -ar 11025 -f mpegts udp://'+address+":"+str(port))
18 | else:
19 | # Create rtsp server for GSTREAMER, require GSTREAMER command installed on pc and a webcam!
20 | stream = os.popen('gst-launch-1.0 autovideosrc device=/dev/videoX ! video/x-raw,width=640,height=480,encoding-name=H264 ! videoconvert ! jpegenc ! udpsink host='+address+' port='+str(port))
21 |
22 | # Use top or activity manager to shutdown the streams if you do not use debugmode! Pycharm loses childprocesses!
23 |
24 | print("Stream active at :" +'udp://'+address+":"+str(port))
25 |
26 | print("Sending stream address to Visulization Stream...")
27 | video_data= {
28 | 'id': 144124,
29 | 'value': 'udp://'+address+":"+str(port),
30 | 'type': 'video_stream',
31 | 'name': 'Video Stream HTTP Example',
32 | 'api_crypt':"password-1"}
33 |
34 | headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
35 | API_ENDPOINT = "http://localhost:8030" # set in config
36 |
37 | import requests
38 | import json
39 | import time
40 | while True:
41 | # sending post request and saving response as response object
42 | requests.post(url=API_ENDPOINT, data=json.dumps(video_data), headers=headers)
43 | time.sleep(2)
44 |
45 |
46 |
47 | """
48 | #Uncomment this if you want to test the rtsp server streams in this program!
49 | import cv2
50 | print(" Test Capture video ")
51 | cap = cv2.VideoCapture("udp://"+address+":"+str(port))
52 | # get list
53 | while True:
54 | ret, frame = cap.read()
55 |
56 | cv2.imshow("test", frame)
57 | cv2.waitKey(1)
58 | """
59 |
60 | while True:
61 | time.sleep(10) # keep thread alive
62 |
63 |
--------------------------------------------------------------------------------
/examples/send_geomarkers.py:
--------------------------------------------------------------------------------
1 |
2 | # importing the requests library
3 | import requests
4 | import time
5 | from random import random
6 | import json
7 |
8 | # defining the api-endpoint
9 | API_ENDPOINT = "http://127.0.0.1:8030"
10 |
11 | CRYPT = "password-1"
12 |
13 | # data to be sent to api
14 |
15 | data = {
16 | 'id':151515,
17 | 'value':'{ center: {lat: 41.40338, lng: 2.17403}, zoom: 4, data: [{lat: 41.40334, lng: 2.17404},{lat: 41.40335, lng: 2.17407} ] }' ,
18 | 'type':'map',
19 | 'name':'Geo Marker Map Example',
20 | 'api_crypt':CRYPT
21 | }
22 | headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
23 |
24 | while True:
25 | print("Sending our POST request to server ...")
26 | print(API_ENDPOINT, data)
27 | # sending post request and saving response as response object
28 | r = requests.post(url = API_ENDPOINT, data = json.dumps(data), headers=headers)
29 |
30 |
31 | time.sleep(15)
32 |
--------------------------------------------------------------------------------
/examples/send_heatmap_data.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import time
3 | from random import random
4 |
5 | """
6 | Stock price stream example for this program
7 | """
8 |
9 | def main():
10 | HOST = '127.0.0.1' # Standard loopback interface address (localhost)
11 | PORT = 65432 # can change this if you want
12 |
13 | # Create a TCP/IP socket
14 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
15 |
16 | # Bind the socket to the port
17 | server_address = (HOST, PORT)
18 |
19 | sock.connect(server_address)
20 | print("start Sending data")
21 | while True:
22 | point = (int(round(random()*192, 3)),int(round(random()*108, 3)))
23 | send_str = '{"id":80085, "value":['+str(point[0])+","+str(point[1])+'], "type":"heatmap","active_points": 20, "width":192, "height":108, "label":["Random Number"], "legend": ["random"], "name":"Random Pos Heatmap", "borderColor":["#3e95cd"], "backgroundColor" :["#3e95cd"]}'
24 | sock.sendall(str.encode(send_str))
25 |
26 | time.sleep(1)
27 |
28 | if __name__ == '__main__':
29 | main()
30 |
--------------------------------------------------------------------------------
/examples/send_heatmap_data_as_image.py:
--------------------------------------------------------------------------------
1 | from VisClient import VisClient
2 | import time
3 | import base64
4 | import random
5 |
6 |
7 | """
8 | This Function is under development and is not currently working!
9 | """
10 | from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
11 | from matplotlib.figure import Figure
12 |
13 | import numpy as np
14 | import matplotlib
15 | import matplotlib.pyplot as plt
16 | import cv2
17 |
18 | pixels = np.zeros((1080, 1920))
19 |
20 | data_heat_value = 1
21 |
22 |
23 | conn = VisClient("127.0.0.1",12345)
24 | print("Creating and sending heatmap to server!!!")
25 | while True:
26 | # Add 100 points
27 | for i in range(0,100):
28 | # Add random point in heatmap
29 | pixels[random.randint(0,1080-1)][random.randint(0,1920-1)] += data_heat_value
30 | fig, ax = plt.subplots()
31 |
32 | im = ax.imshow(pixels)
33 |
34 |
35 | ax.set_title("Heatmap Example")
36 | fig.tight_layout()
37 |
38 | fig.canvas.draw()
39 |
40 | #plt.show()
41 |
42 | image = np.array(fig.canvas.renderer._renderer)
43 |
44 | #cv2.imshow("test", image)
45 | #cv2.waitKey(1)
46 |
47 | retval, buffer = cv2.imencode('.png', image)
48 | encoded_string = "data:image/png;base64,"+base64.b64encode(buffer).decode()
49 |
50 | send_string = '{"id":696969969, "value":"'+encoded_string+'", "type":"image","name":""}'
51 |
52 | plt.close(fig)
53 |
54 | conn.send_large(send_string)
55 |
56 | time.sleep(2)
57 |
--------------------------------------------------------------------------------
/examples/send_post_request_to_HTTP_server.py:
--------------------------------------------------------------------------------
1 |
2 | # importing the requests library
3 | import requests
4 | import time
5 | from random import random
6 | import json
7 |
8 | # defining the api-endpoint
9 | API_ENDPOINT = "http://127.0.0.1:8030"
10 |
11 | CRYPT = "password-1"
12 |
13 | # data to be sent to api
14 | data = {
15 | 'id':223322,
16 | 'value':[round(random()*100, 3)],
17 | 'type':'line',
18 | 'active_points': 20,
19 | 'label':['Random Number'],
20 | 'legend': ['random'],
21 | 'name':'Random Number Example',
22 | 'borderColor':['#3e95cd'],
23 | 'backgroundColor':['#3e95cd'],
24 | 'api_crypt':CRYPT
25 | }
26 | headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
27 |
28 | while True:
29 | print("Sending our POST request to server ...")
30 | print(API_ENDPOINT, data)
31 | # sending post request and saving response as response object
32 | r = requests.post(url = API_ENDPOINT, data = json.dumps(data), headers=headers)
33 |
34 |
35 | time.sleep(5)
36 |
--------------------------------------------------------------------------------
/examples/send_random_number_stream.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import time
3 | from random import random
4 |
5 | """
6 | Stock price stream example for this program
7 | """
8 |
9 | def main():
10 | HOST = '127.0.0.1' # Standard loopback interface address (localhost)
11 | PORT = 65432 # can change this if you want
12 |
13 | # Create a TCP/IP socket
14 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
15 |
16 | # Bind the socket to the port
17 | server_address = (HOST, PORT)
18 |
19 | sock.connect(server_address)
20 |
21 | while True:
22 |
23 | send_str = '{"id":80085, "value":['+str(round(random()*100, 3))+'], "type":"line","active_points": 20, "label":["Random Number"], "legend": ["random"], "name":"Random Number Example", "borderColor":["#3e95cd"], "backgroundColor" :["#3e95cd"]}'
24 | sock.sendall(str.encode(send_str))
25 |
26 | time.sleep(0.5)
27 |
28 | if __name__ == '__main__':
29 | main()
30 |
--------------------------------------------------------------------------------
/examples/send_stock_price_stream.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import time
3 |
4 | from yahoo_fin import stock_info as si
5 |
6 | """
7 | Stock price stream example for this program
8 | """
9 |
10 | def main():
11 | HOST = '127.0.0.1' # Standard loopback interface address (localhost)
12 | PORT = 65432 # can change this if you want
13 |
14 | # Create a TCP/IP socket
15 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
16 |
17 | # Bind the socket to the port
18 | server_address = (HOST, PORT)
19 |
20 | sock.connect(server_address)
21 |
22 | while True:
23 | # get live price of Apple
24 | apple = si.get_live_price("aapl")
25 |
26 | # or Amazon
27 | amazon = si.get_live_price("amzn")
28 |
29 | print("apple: " ,apple,"amazon: ", amazon)
30 |
31 | send_str = '{"id":1337, "value": ['+str(apple)+', '+ str(amazon)+'], "type":"line","active_points": 20, "label":"Share Price ($)", "legend": ["apple", "amazon"], "name":"Stock Share Prices Example", "borderColor":["#3e95cd", "#e8c3b9"], "backgroundColor" :["#3e95cd","#e8c3b9"]}'
32 | sock.sendall(str.encode(send_str))
33 |
34 | time.sleep(2)
35 |
36 | if __name__ == '__main__':
37 | main()
38 |
--------------------------------------------------------------------------------
/examples/send_text_stream.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import time
3 |
4 | """
5 | Stock price stream example for this program
6 | """
7 | import random
8 | import string
9 |
10 | def randomString(stringLength=10):
11 | """Generate a random string of fixed length """
12 | letters = string.ascii_lowercase
13 | return ''.join(random.choice(letters) for i in range(stringLength))
14 |
15 | def main():
16 | HOST = '127.0.0.1' # Standard loopback interface address (localhost)
17 | PORT = 65432 # can change this if you want
18 |
19 | # Create a TCP/IP socket
20 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
21 |
22 | # Bind the socket to the port
23 | server_address = (HOST, PORT)
24 |
25 | sock.connect(server_address)
26 | print("Start sending random text")
27 | while True:
28 |
29 | send_str = '{"id":80085, "value":"'+randomString(random.randint(1,50))+'", "type":"text","active_points": 20, "name":"Random Text Example", "borderColor":["#ffffff"], "backgroundColor" :["#000000"]}'
30 | sock.sendall(str.encode(send_str))
31 |
32 | time.sleep(0.5)
33 |
34 | if __name__ == '__main__':
35 | main()
36 |
--------------------------------------------------------------------------------
/examples/send_webcam_images.py:
--------------------------------------------------------------------------------
1 |
2 | from VisClient import VisClient
3 | import time
4 | import cv2
5 | import base64
6 | import threading
7 |
8 |
9 | class sender(threading.Thread):
10 | def __init__(self, conn, image):
11 | super(sender,self).__init__()
12 | self.done = True
13 | self.conn = conn
14 | self.image = image
15 | def is_done(self):
16 | return self.done
17 |
18 | def run(self):
19 | self.done = False
20 | retval, buffer = cv2.imencode('.png', self.image)
21 | encoded_string = "data:image/png;base64,"+base64.b64encode(buffer).decode()
22 | send_string = '{"id":69696969, "value":"'+encoded_string+'", "type":"image","name":"Webcam Stream"}'
23 | self.conn.send_large(send_string)
24 | self.done = True
25 |
26 |
27 |
28 | cap = cv2.VideoCapture(0)
29 | conn = VisClient("127.0.0.1",12345)
30 | extra_thread = None
31 | print("Sending Images with one sec delay")
32 | while True:
33 | time.sleep(2)
34 | ret, image = cap.read()
35 |
36 | if extra_thread is None:
37 | extra_thread = sender(conn, image)
38 | extra_thread.start()
39 | else:
40 |
41 | if extra_thread.is_done() :
42 | extra_thread = sender(conn, image)
43 | extra_thread.start()
44 |
45 | #time.sleep(1)
46 |
47 | #cv2.imshow("test", image)
48 | #cv2.waitKey(1)
49 |
--------------------------------------------------------------------------------
/flask_handler.py:
--------------------------------------------------------------------------------
1 | #from gevent import monkey
2 | #monkey.patch_all()
3 |
4 | #import eventlet
5 | #eventlet.monkey_patch()
6 |
7 |
8 | from flask_socketio import SocketIO, emit
9 | from flask import Flask,Response, render_template, url_for, copy_current_request_context
10 |
11 | from threading import Thread, Event
12 | from scheduler import scheduler
13 | from socket_server import SocketServer
14 |
15 | """
16 | Flask handler manages the start and connection to Flask website/server.
17 | """
18 |
19 | app = Flask(__name__, static_url_path='/static')
20 | app.config['DEBUG'] = False # let this be false to only start one webbrowser
21 | app.config['THREADED'] = True
22 |
23 | #turn the flask app into a socketio app
24 | socketio = SocketIO(app, async_mode="threading")
25 |
26 | thread = Thread() # scheduler thread
27 | thread_stop_event = Event()
28 |
29 | #lock = threading.Lock()
30 |
31 | def start_flask_application():
32 | from config_handler import ConfigHandler
33 | [HOST,PORT] = ConfigHandler().get_all("Flask") # pylint: disable=unbalanced-tuple-unpacking
34 | socketio.run(app, host=HOST, port=PORT) # SocketIOServer
35 | app.run(host=HOST, port=PORT) # Other Server
36 |
37 | @app.route('/')
38 | def index():
39 | #only by sending this page first will the client be connected to the socketio instance
40 | return render_template('index.html')
41 |
42 | # For camear
43 | vcapture_list = []
44 | def gen(device):
45 | import cv2
46 | try:
47 | if(device in vcapture_list):
48 | print("Device stream already streaming " + str(device))
49 | vcap = cv2.VideoCapture(device)
50 | vcapture_list.append(device)
51 | while True:
52 | ret, frame = vcap.read()
53 | if frame is None:
54 | continue
55 | (flag, encodedImage) = cv2.imencode(".jpg", frame)
56 | if not flag:
57 | continue
58 | yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
59 | bytearray(encodedImage) + b'\r\n')
60 | except Exception:
61 | print("Capture failed " + str(device))
62 |
63 | @app.route('/video_feed/')
64 | def video_feed(device):
65 | # return the response generated along with the specific media
66 | # type (mime type)
67 | print(device)
68 | device = device.replace("skipableslash","/")
69 | print(device)
70 | try:
71 | return Response(gen(int(device)),mimetype = "multipart/x-mixed-replace; boundary=frame")
72 | except Exception:
73 | return Response(gen(device),mimetype = "multipart/x-mixed-replace; boundary=frame")
74 |
75 | @socketio.on('connect', namespace='/test')
76 | def test_connect():
77 | # need visibility of the global thread object
78 | global thread
79 | print('Flask Client connected')
80 |
81 | #Start the generator threads only if the thread has not been started before.
82 | if not thread.isAlive():
83 | scheduler()
84 |
85 | @socketio.on('disconnect', namespace='/test')
86 | def test_disconnect():
87 | print('Flask Client disconnected')
88 |
--------------------------------------------------------------------------------
/http_client.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from threading import Thread
3 | import json
4 | import time
5 | """
6 | This simple socket client
7 | connects to our socket server and sends live stream numbers
8 | to be displayed in flask.
9 | """
10 |
11 | class HTTPClient(Thread):
12 |
13 | def __init__(self):
14 | super(HTTPClient, self).__init__()
15 |
16 | def run(self):
17 | from config_handler import ConfigHandler
18 | (HOST, PORT, CRYPT) = ConfigHandler().get_all("HTTPServer") # pylint: disable=unbalanced-tuple-unpacking
19 |
20 | data = {
21 | 'id': 12,
22 | 'value': [10],
23 | 'type': 'line',
24 | 'active_points': 20,
25 | 'label': ['Random HTTP Number'],
26 | 'legend': ['random'],
27 | 'name': 'HTTP Example',
28 | 'borderColor': ['#3e95cd'],
29 | 'backgroundColor': ['#3e95cd'],
30 | 'api_crypt':CRYPT
31 | }
32 |
33 | """
34 | video_data= {
35 | 'id': 12,
36 | 'value': 0,
37 | 'type': 'video_stream',
38 | 'name': 'Video Stream HTTP Example',
39 | 'api_crypt':CRYPT
40 | }
41 | """
42 |
43 | headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
44 | API_ENDPOINT = "http://"+HOST+":"+PORT
45 |
46 | while True:
47 | # sending post request and saving response as response object
48 | requests.post(url=API_ENDPOINT, data=json.dumps(data), headers=headers)
49 | time.sleep(2)
50 |
51 |
--------------------------------------------------------------------------------
/http_server.py:
--------------------------------------------------------------------------------
1 | """
2 | This server will receive HTTP post requests and send the data to flask
3 | """
4 | from threading import Thread
5 | from data_stream import send_request
6 | import http.server
7 | import json
8 | from functools import partial
9 | from http.server import BaseHTTPRequestHandler, HTTPServer
10 |
11 | class S(BaseHTTPRequestHandler):
12 |
13 | def __init__(self, CRYPT="password-1", *args, **kwargs):
14 | self.CRYPT = CRYPT
15 | super().__init__(*args, **kwargs)
16 |
17 |
18 |
19 | def _set_response(self):
20 | self.send_response(200, "ok")
21 | self.send_header('Access-Control-Allow-Origin', '*')
22 | self.send_header('Access-Control-Allow-Methods', 'POST, OPTIONS, HEAD, GET')
23 | self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
24 | self.send_header("Access-Control-Allow-Headers", "Content-Type")
25 | self.send_header('Content-type', 'application/json')
26 | self.end_headers()
27 |
28 | def do_HEAD(self):
29 | self._set_response()
30 |
31 | def do_OPTIONS(self):
32 | self._set_response()
33 |
34 | def do_POST(self):
35 | #print(self.client_address,self.headers)
36 |
37 | if self.headers['Content-Length']:
38 |
39 | content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
40 | post_data = self.rfile.read(content_length) # <--- Gets the data itself
41 | # decode incoming data // see if password is correct here!
42 | try:
43 | #print("data",post_data)
44 | data = json.loads(post_data)
45 | #print("json", data)
46 | if data['api_crypt'] :
47 | if data['api_crypt'] == self.CRYPT:
48 |
49 | print("Sending request " + str(data["value"]))
50 | send_request(id = data["id"], data=data["value"], type =safe(data, "type"), active_points =safe(data, "active_points"),
51 | _label=safe(data, "label"), _legend=safe(data, "legend"), _width = safe(data, "width"), _height = safe(data, "height"),
52 | _name = safe(data, "name"), fill = safe(data, "fill"), backgroundColor = safe(data, "backgroundColor"),
53 | borderColor = safe(data, "borderColor"))
54 | except Exception as e:
55 | print("ERROR: "+str(e))
56 | self._set_response()
57 |
58 | class HTTPserver(Thread):
59 |
60 | def __init__(self):
61 | super().__init__()
62 |
63 | def run(self):
64 | from config_handler import ConfigHandler
65 | (HOST, PORT, CRYPT) = ConfigHandler().get_all("HTTPServer") # pylint: disable=unbalanced-tuple-unpacking
66 | server_address = (str(HOST),int(PORT))
67 | httpd = HTTPServer(server_address, partial(S, CRYPT))
68 | try:
69 | httpd.serve_forever()
70 | except KeyboardInterrupt:
71 | pass
72 | httpd.server_close()
73 |
74 | def safe(json, value):
75 | try:
76 | return json[value]
77 | except Exception:
78 | return
79 |
--------------------------------------------------------------------------------
/image_server.py:
--------------------------------------------------------------------------------
1 | import time
2 | import json
3 | import cv2
4 | import pickle
5 | import struct
6 | from threading import Thread, Event
7 | from data_stream import send_request
8 | import socket
9 |
10 | """
11 | ImageServer is a multithreaded socket server
12 | This server is used to send larger packages to Flask
13 | receiving n amount of connections and proxy the messages
14 | to flask
15 | """
16 |
17 | class ImageServer(Thread):
18 | def __init__(self):
19 | super(ImageServer, self).__init__()
20 |
21 | def handle_connection(self, conn):
22 | with conn:
23 | while True:
24 | data = b""
25 | payload_size = struct.calcsize(">L")
26 | try:
27 | # Recieve image package size
28 | while len(data) < payload_size:
29 | data += conn.recv(4096)
30 |
31 | packed_msg_size = data[:payload_size]
32 | data = data[payload_size:]
33 | msg_size = struct.unpack(">L", packed_msg_size)[0]
34 |
35 | # Recieve image
36 | while len(data) < msg_size:
37 | data += conn.recv(4096)
38 | frame_data = data[:msg_size]
39 | data = data[msg_size:]
40 |
41 | data=pickle.loads(frame_data, fix_imports=True, encoding="bytes")
42 | data = json.loads(data)
43 |
44 | send_request(id = data["id"], data=data["value"], type =safe(data, "type"), active_points =safe(data, "active_points"),
45 | _label=safe(data, "label"), _legend=safe(data, "legend"), _width = safe(data, "width"), _height = safe(data, "height"),
46 | _name = safe(data, "name"), fill = safe(data, "fill"), backgroundColor = safe(data, "backgroundColor"), borderColor = safe(data, "borderColor"))
47 | except Exception :
48 | pass
49 | # Got corrupt image data1
50 | #print(" WARNING: an error occured in image_server: ", e)
51 |
52 |
53 | def run(self):
54 | from config_handler import ConfigHandler
55 | (HOST, PORT) = ConfigHandler().get_all("ImageServer") # pylint: disable=unbalanced-tuple-unpacking
56 |
57 | #HOST = '127.0.0.1' # Standard loopback interface address (localhost)
58 | #PORT = 12345 # Port to listen on (non-privileged ports are > 1023)
59 |
60 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
61 | s.bind((str(HOST), int(PORT)))
62 | s.listen()
63 | try:
64 | while True:
65 | conn, addr = s.accept()
66 | print('Connected by', addr)
67 | Thread(target=self.handle_connection, args=(conn,)).start()
68 | except Exception as e:
69 | print(e)
70 |
71 | def safe(json, value):
72 | try:
73 | return json[value]
74 | except Exception:
75 | return
76 |
--------------------------------------------------------------------------------
/images/chartjs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/chartjs.png
--------------------------------------------------------------------------------
/images/demo1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/demo1.PNG
--------------------------------------------------------------------------------
/images/demo1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/demo1.gif
--------------------------------------------------------------------------------
/images/demo2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/demo2.gif
--------------------------------------------------------------------------------
/images/flask_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/flask_logo.png
--------------------------------------------------------------------------------
/images/jquery.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/jquery.jpg
--------------------------------------------------------------------------------
/images/plotly.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/plotly.png
--------------------------------------------------------------------------------
/images/python.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/python.png
--------------------------------------------------------------------------------
/images/structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grebtsew/Visualize-Realtime-Data-Stream-Chart-in-Flask/c9c5cee4d8f231d28744d1ae7de231e13981f4b1/images/structure.png
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from flask_handler import start_flask_application, app
2 | import webbrowser
3 | import threading
4 | import functools
5 | from config_handler import ConfigHandler
6 |
7 | """
8 | Start Program with this file by running "python3 start.py"
9 | """
10 |
11 | [HOST, PORT] = ConfigHandler().get_all("Website") # pylint: disable=unbalanced-tuple-unpacking
12 |
13 | url = "http://"+HOST+":{0}".format(PORT)
14 |
15 | if __name__ == '__main__':
16 | threading.Timer(1, functools.partial( webbrowser.open, url )).start()
17 | start_flask_application()
18 |
19 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask-SocketIO==4.2.1
2 | Flask==1.1.1
3 | yahoo-fin==0.8.2
4 | opencv-python>=3.4.1.15
5 | requests>=2.23.0
6 | ConfigParser>=4.0.2
--------------------------------------------------------------------------------
/scheduler.py:
--------------------------------------------------------------------------------
1 | # include new streams to start in this file
2 |
3 | from data_streams.samples import samplelist, random_nr_config, random_nr
4 |
5 | from socket_client import SocketClient
6 | from socket_server import SocketServer
7 | from image_server import ImageServer
8 | from data_stream import DataStream
9 | from http_client import HTTPClient
10 | from http_server import HTTPserver
11 |
12 | import threading
13 |
14 | """
15 | Scheduler starts the SocketServer and local data streams when
16 | flask server is up and running.
17 | """
18 |
19 | def scheduler():
20 | """
21 | Start all streams
22 | """
23 | print("Flask up and running, now starting data streams...")
24 |
25 | # Start TCP socket Server
26 | SocketServer().start()
27 | print("SocketServer Started")
28 | ImageServer().start()
29 | print("ImageServer Started")
30 | # Start HTTP server
31 | HTTPserver().start()
32 | print("HTTPServer Started")
33 | # Can be a smart idea to start streams here!
34 | # Start some demo flows
35 | #demo()
36 |
37 | def demo():
38 |
39 | # Start Example TCP socket client
40 | for message in samplelist: # see samplelist in /data_streams/samples.py
41 | SocketClient(message=message).start()
42 |
43 | # Start HTTP example client
44 | HTTPClient().start()
45 |
46 | # Start Example Random Number Stream
47 | DataStream(random_nr_config, random_nr).start()
48 |
--------------------------------------------------------------------------------
/socket_client.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import time
3 | from threading import Thread
4 |
5 | """
6 | This simple socket client
7 | connects to our socket server and sends live stream numbers
8 | to be displayed in flask.
9 | """
10 |
11 | class SocketClient(Thread):
12 |
13 | def __init__(self, message):
14 | super(SocketClient, self).__init__()
15 | self.message = message
16 |
17 | def run(self):
18 | from config_handler import ConfigHandler
19 | (HOST, PORT) = ConfigHandler().get_all("SocketServer") # pylint: disable=unbalanced-tuple-unpacking
20 |
21 | #HOST = '127.0.0.1' # Standard loopback interface address (localhost)
22 | #PORT = 65432 # can change this if you want
23 |
24 | # Create a TCP/IP socket
25 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
26 |
27 | # Bind the socket to the port
28 | server_address = (str(HOST), int(PORT))
29 |
30 | sock.connect(server_address)
31 |
32 | while True:
33 | sock.sendall(str.encode(self.message))
34 | time.sleep(2)
35 |
--------------------------------------------------------------------------------
/socket_server.py:
--------------------------------------------------------------------------------
1 | import time
2 | import json
3 | from threading import Thread, Event
4 | import socket
5 | from data_stream import send_request
6 |
7 | """
8 | SocketServer is a multithreaded socket server
9 | receiving n amount of connections and proxy the messages
10 | to flask
11 | """
12 |
13 | class SocketServer(Thread):
14 | def __init__(self):
15 | super(SocketServer, self).__init__()
16 |
17 | def handle_connection(self, conn):
18 | with conn:
19 | while True:
20 | data = conn.recv(1024)
21 | if not data:
22 | break
23 | else:
24 | #print(data)
25 | try:
26 |
27 | data = json.loads(data)
28 | send_request(id = data["id"], data=data["value"], type =safe(data, "type"), active_points =safe(data, "active_points"),
29 | _label=safe(data, "label"), _legend=safe(data, "legend"), _width = safe(data, "width"), _height = safe(data, "height"),
30 | _name = safe(data, "name"), fill = safe(data, "fill"), backgroundColor = safe(data, "backgroundColor"), borderColor = safe(data, "borderColor"))
31 | except Exception as e:
32 |
33 | print(data)
34 | print(" WARNING: an error occured in socket_server: ", e)
35 |
36 |
37 | def run(self):
38 | from config_handler import ConfigHandler
39 | (HOST, PORT) = ConfigHandler().get_all("SocketServer") # pylint: disable=unbalanced-tuple-unpacking
40 |
41 | #HOST = '127.0.0.1' # Standard loopback interface address (localhost)
42 | #PORT = 65432 # Port to listen on (non-privileged ports are > 1023)
43 |
44 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
45 | s.bind((str(HOST), int(PORT)))
46 | s.listen()
47 | try:
48 | while True:
49 | conn, addr = s.accept()
50 | print('Connected by', addr)
51 | Thread(target=self.handle_connection, args=(conn,)).start()
52 | except Exception as e:
53 | print(e)
54 |
55 | def safe(json, value):
56 | try:
57 | return json[value]
58 | except Exception:
59 | return
60 |
--------------------------------------------------------------------------------
/static/css/style.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .collapsible {
4 | background-color: blue;
5 | color: white;
6 | cursor: pointer;
7 | padding: 18px;
8 | width: 100%;
9 | border: none;
10 | text-align: left;
11 | outline: none;
12 | font-size: 15px;
13 | }
14 |
15 | .active, .collapsible:hover {
16 | background-color: #555;
17 | }
18 |
19 | .content {
20 | padding: 0 18px;
21 | display: none;
22 | overflow: hidden;
23 | background-color: #f1f1f1;
24 | }
25 |
26 | .slidecontainer {
27 | width: 100%;
28 | background: blue;
29 | }
30 |
31 | .slider {
32 | -webkit-appearance: none;
33 | width: 200px;
34 | height: 25px;
35 | background: slategray;
36 | outline: none;
37 | opacity: 0.7;
38 | -webkit-transition: .2s;
39 | transition: opacity .2s;
40 | }
41 |
42 | .slider:hover {
43 | opacity: 1;
44 | }
45 |
46 | .slider::-webkit-slider-thumb {
47 | -webkit-appearance: none;
48 | appearance: none;
49 | width: 25px;
50 | height: 25px;
51 | background: blue;
52 | cursor: pointer;
53 | }
54 |
55 | .slider::-moz-range-thumb {
56 | width: 25px;
57 | height: 25px;
58 | background: blue;
59 | cursor: pointer;
60 | }
61 |
--------------------------------------------------------------------------------
/templates/camera_sample.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Pi Video Surveillance
4 |
5 |
6 | Pi Video Surveillance
7 |
8 |
9 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Creating Real-Time Charts with Flask
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
640 |
641 |
642 |
643 |
644 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
693 |
694 |
695 |
696 |
697 |
--------------------------------------------------------------------------------
/templates/map_sample.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Add a raster tile source
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
46 |
47 |
48 |
--------------------------------------------------------------------------------