Huge refactoring

This commit is contained in:
Darko Lukic 2018-03-25 00:27:19 +01:00
parent 2ee2a97d40
commit b9a5c577a0
50 changed files with 165 additions and 130 deletions

13
backend/database_cleaning.py → bin/dbcleaner Normal file → Executable file
View file

@ -1,15 +1,17 @@
#!/usr/bin/env python
'''
This program will clean the sqlite database every now and then to keep it from exploding.
'''
import time
import sqlite3
import configparser
import random
from cosmicpi.config import Config as config
import logging as log
log.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=log.INFO)
@ -25,15 +27,12 @@ def _initilize_DB(_sqlite_location):
_db_conn.commit()
# settings files
CONFIG_FILE = "../config/CosmicPi.config"
# read configuration
# Todo: Put the config parser into a propper class
# Todo: Implement proper error catching for configparser (e.g. non existent keys or file)
# read configuration
config = configparser.ConfigParser()
config.read(CONFIG_FILE)
sqlite_location = config.get("Storage", "sqlite_location")
max_event_age = config.getint("Storage", "sqlite_max_event_age") * 60. * 60. # here used in seconds

9
backend/detector_connect.py → bin/detector Normal file → Executable file
View file

@ -1,3 +1,5 @@
#!/usr/bin/env python
'''
This program manages the connection to an attached detector.
@ -18,7 +20,7 @@ import sqlite3
import copy
import datetime
from serial import SerialException
import configparser
from cosmicpi.config import Config as config
import logging as log
log.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=log.INFO)
@ -292,15 +294,10 @@ class CosmicPi_V15(detector, threading.Thread):
#det = detector("Test1", "TestVersion1", config_sqlite_location)
#det._commit_event_dict(det._example_event_dict)
# settings files
CONFIG_FILE = "../config/CosmicPi.config"
# read configuration
# Todo: Put the config parser into a propper class
# Todo: Implement proper error catching for configparser (e.g. non existent keys or file)
# read configuration
config = configparser.ConfigParser()
config.read(CONFIG_FILE)
detector_class = config.get("Detector", "detector_class")
sqlite_location = config.get("Storage", "sqlite_location")

7
backend/mqtt_publisher.py → bin/mqtt Normal file → Executable file
View file

@ -1,3 +1,5 @@
#!/usr/bin/env python
'''
This program will check the database about every minute to search for a new event.
If one is found it will be sent to an mqtt server
@ -13,6 +15,7 @@ import json
import subprocess
import socket
import struct
from cosmicpi.config import Config as config
import logging as log
log.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=log.INFO)
@ -67,15 +70,11 @@ def send_via_mqtt(broker_address, broker_topic, message):
# ToDo: This is unsafe, though there should be no user data here the risk of code injection is low.
subprocess.call(execution_string, shell=True)
# settings files
CONFIG_FILE = "../config/CosmicPi.config"
# read configuration
# Todo: Put the config parser into a propper class
# Todo: Implement proper error catching for configparser (e.g. non existent keys or file)
# read configuration
config = configparser.ConfigParser()
config.read(CONFIG_FILE)
sqlite_location = config.get("Storage", "sqlite_location")
broker_address = config.get("MQTT", "broker_address")
broker_topic = "{}/{}".format(config.get("MQTT", "broker_topic"), getserial())

7
bin/rest Executable file
View file

@ -0,0 +1,7 @@
#!/usr/bin/env python
from cosmicpi.rest.app import create_app
if __name__ == '__main__':
app = create_app()
app.run(debug=True, host='0.0.0.0')

24
bin/ui Executable file
View file

@ -0,0 +1,24 @@
#!/usr/bin/env python
from flask import send_from_directory
from cosmicpi.rest.app import create_app
import cosmicpi.ui
import os
path = os.path.abspath(cosmicpi.ui.__file__)
UI_DIR = os.path.dirname(path)
if __name__ == '__main__':
app = create_app()
@app.route('/dist/<path:path>')
def serve_page(path):
return send_from_directory(os.path.join(UI_DIR, 'dist'), path)
@app.route('/')
def server_index():
return send_from_directory(UI_DIR, 'index.html')
app.run(debug=True, host='0.0.0.0')

14
cosmicpi/config.py Normal file
View file

@ -0,0 +1,14 @@
import configparser
import os
import cosmicpi.storage
Config = configparser.ConfigParser()
Config.read(['install_files/cosmicpi.config', '/etc/cosmicpi.conf'])
# Set SQLite database path if not exist in config
if not Config.has_option('Storage', 'sqlite_location'):
storage_path = os.path.abspath(cosmicpi.storage.__file__)
sqlite_path = os.path.join(os.path.dirname(storage_path), 'sqlite_db')
Config.set('Storage', 'sqlite_location', sqlite_path)

View file

@ -1,10 +1,9 @@
# CosmicPi REST API
## Development
Make sure that CosmicPi UI service does not run (`sudo systemctl stop CosmicPi-UI`),
navigate to `/rest` and run:
Navigate to `/` and run:
```
FLASK_DEBUG=1 FLASK_APP=${PWD}/app.py python -m flask run --host=0.0.0.0
PYTHONPATH=. ./bin/ui
```
## API

23
cosmicpi/rest/app.py Normal file
View file

@ -0,0 +1,23 @@
from flask import Flask, request
from flask_restful import Api
from flask_cors import CORS
from .wifi import Wifi
from .histogram import Histogram
from .series import Series
from .auth import Auth
def create_app():
app = Flask(__name__)
api = Api(app)
CORS(app, resources=r'/api/*')
api.add_resource(Auth, '/api/auth')
api.add_resource(Wifi, '/api/wifi')
api.add_resource(Histogram, '/api/histogram.png')
api.add_resource(Series, '/api/series')
return app
if __name__ == '__main__':
create_app().run(debug=True)

View file

@ -1,6 +1,6 @@
from flask import request
from flask_restful import Resource, abort
from .config import Config
from cosmicpi.config import Config
from functools import wraps

View file

@ -6,7 +6,7 @@ import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import io
import sqlite3
from .config import Config
from cosmicpi.config import Config
SQLITE_LOCATION = Config.get("Storage", "sqlite_location")

View file

@ -1,6 +1,6 @@
from flask import request, make_response
from flask_restful import Resource
from .config import Config
from cosmicpi.config import Config
import sqlite3
import io
import csv

View file

@ -1,13 +1,19 @@
from flask import request
from flask_restful import Resource
from .config import Config
from cosmicpi.config import Config
from .auth import requires_auth
import subprocess
import re
import time
import thread
import urllib2
from functools import wraps
try:
import thread
except:
import _thread as thread
try:
import urllib2
except:
import urllib3 as urllib2
DEFAULT_WIFI_NAME = Config.get("Default WiFi", "name")

View file

0
cosmicpi/ui/__init__.py Normal file
View file

View file

@ -1423,10 +1423,16 @@
"dev": true,
"requires": {
"base64-js": "1.2.3",
"ieee754": "1.1.10",
"ieee754": "1.1.11",
"isarray": "1.0.0"
}
},
"buffer-from": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz",
"integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==",
"dev": true
},
"buffer-indexof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
@ -1998,11 +2004,12 @@
"dev": true
},
"concat-stream": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.1.tgz",
"integrity": "sha512-gslSSJx03QKa59cIKqeJO9HQ/WZMotvYJCuaUULrLpjj8oG40kV2Z+gz82pVxlTkOADi4PJxQPPfhl1ELYrrXw==",
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"dev": true,
"requires": {
"buffer-from": "1.0.0",
"inherits": "2.0.3",
"readable-stream": "2.3.5",
"typedarray": "0.0.6"
@ -3275,9 +3282,9 @@
"dev": true
},
"flush-write-stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz",
"integrity": "sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
"integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==",
"dev": true,
"requires": {
"inherits": "2.0.3",
@ -4927,9 +4934,9 @@
}
},
"ieee754": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.10.tgz",
"integrity": "sha512-byWFX8OyW/qeVxcY21r6Ncxl0ZYHgnf0cPup2h34eHXrCJbOp7IuqnJ4Q0omfyWl6Z++BTI6bByf31pZt7iRLg==",
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz",
"integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==",
"dev": true
},
"iferr": {
@ -5476,7 +5483,7 @@
"neo-async": "2.5.0",
"node-dir": "0.1.8",
"nomnom": "1.8.1",
"recast": "0.14.5",
"recast": "0.14.7",
"temp": "0.8.3",
"write-file-atomic": "1.3.4"
},
@ -6139,9 +6146,9 @@
},
"dependencies": {
"clone": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz",
"integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
"dev": true
},
"clone-stats": {
@ -6162,7 +6169,7 @@
"integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=",
"dev": true,
"requires": {
"clone": "2.1.1",
"clone": "2.1.2",
"clone-buffer": "1.0.0",
"clone-stats": "1.0.0",
"cloneable-readable": "1.1.2",
@ -6316,10 +6323,10 @@
"integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==",
"dev": true,
"requires": {
"concat-stream": "1.6.1",
"concat-stream": "1.6.2",
"duplexify": "3.5.4",
"end-of-stream": "1.4.1",
"flush-write-stream": "1.0.2",
"flush-write-stream": "1.0.3",
"from2": "2.3.0",
"parallel-transform": "1.1.0",
"pump": "2.0.1",
@ -9249,9 +9256,9 @@
}
},
"recast": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/recast/-/recast-0.14.5.tgz",
"integrity": "sha512-GNFQGQrqW1R8w9XhhgYIN8H7ePPp088D+svHlb7DdP5DCqNDqTwH7lt378EouM+L18kCwkmqpAz1unLqpPhHmw==",
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/recast/-/recast-0.14.7.tgz",
"integrity": "sha512-/nwm9pkrcWagN40JeJhkPaRxiHXBRkXyRh/hgU088Z/v+qCy+zIHHY6bC6o7NaKAxPqtE6nD8zBH1LfU0/Wx6A==",
"dev": true,
"requires": {
"ast-types": "0.11.3",
@ -10944,9 +10951,9 @@
"dev": true
},
"vue-loader": {
"version": "14.2.1",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-14.2.1.tgz",
"integrity": "sha512-QSsDSWzKYxyC2LHpp9+2oteUg/ObHeP1VkZAiFTtkTR3lBV7mobcfxzHdQl9mBeJEjdCZpjzWiIUCAErE0K1EA==",
"version": "14.2.2",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-14.2.2.tgz",
"integrity": "sha512-SehrPGsxSssZXQoR7DTAm2oMBiJxV+xTIX5BUxc+qFsNo0iIj01tzAMXWt0PD5hjoNCXdS5Bq1KLRy7WaMdkKg==",
"dev": true,
"requires": {
"consolidate": "0.14.5",
@ -11037,9 +11044,9 @@
}
},
"webpack": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.1.1.tgz",
"integrity": "sha512-PwxKH81yLjbPyBSZvPj/Ji9pT99XOGFA0t6zipoOKOMNRZ+09N39J5Uzcx3rYKnsHgKwDnfGkvzac4MF2Taknw==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.2.0.tgz",
"integrity": "sha512-O/KmJ2MYoSfsZzq3//RyyYICYTb1gPAuYSIoD4XbxWFqkDrZCkF8BIAwPuFjA8SFqTcsIL3gTS7hiTZaUN2Tjw==",
"dev": true,
"requires": {
"acorn": "5.5.3",
@ -11218,9 +11225,9 @@
}
},
"webpack-cli": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.0.12.tgz",
"integrity": "sha512-kMi6NquWwUhmQok2IFrtAEIbaVvujzYvtDGb5WElkwylbLboDsCgizv8IjSi/Q6SQRJ8Crayl1JCBnIJ3rU4Rg==",
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.0.13.tgz",
"integrity": "sha512-0lnOi3yla8FsZVuMsbfnNRB/8DlfuDugKdekC+4ykydZG0+UOidMi5J5LLWN4c0VJ8PqC19yMXXkYyCq78OuqA==",
"dev": true,
"requires": {
"chalk": "2.3.2",

View file

@ -5,7 +5,7 @@
"main": "webpack.config.js",
"scripts": {
"dev": "webpack-dev-server --open --mode development --disable-host-check --host 0.0.0.0",
"build": "webpack --progress --mode production",
"build": "NODE_ENV=production webpack --mode production",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
@ -16,7 +16,6 @@
],
"author": "",
"license": "ISC",
"sideEffects": false,
"dependencies": {
"bootstrap": "^4.0.0",
"chart.js": "^2.7.2",
@ -36,10 +35,10 @@
"file-loader": "^1.1.11",
"style-loader": "^0.20.3",
"url-loader": "^1.0.1",
"vue-loader": "^14.2.1",
"vue-loader": "^14.2.2",
"vue-template-compiler": "^2.5.16",
"webpack": "^4.1.1",
"webpack-cli": "^2.0.12",
"webpack": "^4.2.0",
"webpack-cli": "^2.0.13",
"webpack-dev-server": "^3.1.1"
}
}

View file

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 188 KiB

View file

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View file

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 112 KiB

View file

@ -1,17 +1,17 @@
import Vue from 'vue'
import Vue from 'vue';
import VueResource from 'vue-resource';
import { Settings } from 'luxon'
import router from './router.js'
import store from './store.js';
import App from './App.vue'
import './assets/css/main.css'
import 'bootstrap/dist/css/bootstrap.css'
import 'font-awesome/css/font-awesome.css'
import 'vue-datetime/dist/vue-datetime.css'
import App from './App.vue';
import './assets/css/main.css';
import 'bootstrap/dist/css/bootstrap.css';
import 'font-awesome/css/font-awesome.css';
import 'vue-datetime/dist/vue-datetime.css';
Vue.use(VueResource);
Vue.http.options.root = 'http://192.168.1.26:5000/api/';
Vue.http.options.root = API_URL;
Settings.defaultLocale = 'en'

View file

@ -66,25 +66,15 @@ module.exports = {
performance: {
hints: false
},
devtool: '#eval-source-map'
devtool: '#eval-source-map',
plugins: [
new webpack.DefinePlugin({
'API_URL': JSON.stringify(process.env.NODE_ENV === 'production' ?
'/api/' : 'http://192.168.1.26:5000/api/'),
})
]
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
module.exports.devtool = '#source-map';
}

View file

@ -1,12 +0,0 @@
[Unit]
Description=Software for the CosmicPi UI
[Service]
# Flask Env Vars
Environment=FLASK_APP=/home/pi/cosmicpi-rpi_V1.5/frontend/web_ui.py
ExecStart=/usr/bin/python -m flask run --host=0.0.0.0 --port=80
WorkingDirectory=/home/pi/cosmicpi-rpi_V1.5/frontend/
Restart=on-failure
[Install]
WantedBy=multi-user.target

View file

@ -2,8 +2,8 @@
Description=Software for cleaning the local database from time to time, to keep it from exploding
[Service]
ExecStart=/usr/bin/python /home/pi/cosmicpi-rpi_V1.5/backend/database_cleaning.py
WorkingDirectory=/home/pi/cosmicpi-rpi_V1.5/backend/
ExecStart=PYTHONPATH=/home/pi/cosmicpi-rpi_V1.5/ /home/pi/cosmicpi-rpi_V1.5/bin/dbcleaner
WorkingDirectory=/home/pi/cosmicpi-rpi_V1.5/
Restart=on-failure
[Install]

View file

@ -2,8 +2,8 @@
Description=Software for connecting to the the CosmicPi detector
[Service]
ExecStart=/usr/bin/python /home/pi/cosmicpi-rpi_V1.5/backend/detector_connect.py
WorkingDirectory=/home/pi/cosmicpi-rpi_V1.5/backend/
ExecStart=PYTHONPATH=/home/pi/cosmicpi-rpi_V1.5/ /home/pi/cosmicpi-rpi_V1.5/bin/detector
WorkingDirectory=/home/pi/cosmicpi-rpi_V1.5/
Restart=on-failure
[Install]

View file

@ -2,8 +2,8 @@
Description=Software for sending locally stored events from the CosmicPi to an MQTT srver
[Service]
ExecStart=/usr/bin/python /home/pi/cosmicpi-rpi_V1.5/backend/mqtt_publisher.py
WorkingDirectory=/home/pi/cosmicpi-rpi_V1.5/backend/
ExecStart=PYTHONPATH=/home/pi/cosmicpi-rpi_V1.5/ /home/pi/cosmicpi-rpi_V1.5/bin/mqtt
WorkingDirectory=/home/pi/cosmicpi-rpi_V1.5/
Restart=on-failure
[Install]

View file

@ -0,0 +1,10 @@
[Unit]
Description=Software for the CosmicPi UI
[Service]
ExecStart=PYTHONPATH=/home/pi/cosmicpi-rpi_V1.5/ /home/pi/cosmicpi-rpi_V1.5/bin/ui
WorkingDirectory=/home/pi/cosmicpi-rpi_V1.5/
Restart=on-failure
[Install]
WantedBy=multi-user.target

View file

@ -10,7 +10,6 @@ baud_rate = 19200
enable_raw_output = False
[Storage]
sqlite_location = ../storage/sqlite_db
# tells the cleanup script how old the oldest event is allowed to be; measured in hours
sqlite_max_event_age = 13

View file

@ -1,21 +0,0 @@
from flask import Flask, request
from flask_restful import Api
from flask_cors import CORS
from .wifi import Wifi
from .histogram import Histogram
from .series import Series
from .auth import Auth
app = Flask(__name__)
api = Api(app)
CORS(app, resources=r'/api/*')
api.add_resource(Auth, '/api/auth')
api.add_resource(Wifi, '/api/wifi')
api.add_resource(Histogram, '/api/histogram.png')
api.add_resource(Series, '/api/series')
if __name__ == '__main__':
app.run(debug=True)

View file

@ -1,5 +0,0 @@
import configparser
Config = configparser.ConfigParser()
Config.read('../config/CosmicPi.config')