29 Commits

Author SHA1 Message Date
Kristjan Komloši
1dc9fecff6 Update README 2021-04-08 22:30:22 +02:00
Kristjan Komlosi
57d10a5ae5 test sign 2021-03-09 22:47:20 +01:00
Kristjan Komlosi
2cc0fd977b Comment out old debug buttons 2021-02-17 23:40:04 +01:00
Kristjan Komlosi
3d3254c4a7 formatting 2020-07-13 13:01:34 +02:00
Kristjan Komlosi
cfe6e3c286 remove old-unused files 2020-07-13 12:13:31 +02:00
Kristjan Komlosi
7a3877b34b remove unused FastCGI configuration file 2020-07-13 11:55:21 +02:00
Kristjan Komlosi
f20dd30292 remove unused config file 2020-07-13 11:54:35 +02:00
Kristjan Komlosi
ef5c87d8d2 removed janky and unused storage module 2020-07-13 11:54:20 +02:00
Kristjan Komlosi
4878df9ca8 Shortened error messages 2020-07-13 11:52:22 +02:00
Kristjan Komlosi
89ea9564c8 fixed onclick binding 2020-06-02 10:45:16 +02:00
Kristjan Komlosi
00c619ce34 fixed typo 2020-06-02 09:53:09 +02:00
Kristjan Komlosi
8f22a6baee removed lighttpd configuration as the defaults work fine 2020-06-02 09:52:40 +02:00
Kristjan Komlosi
fa2c1cccb1 removed old pipfiles 2020-06-02 09:52:08 +02:00
Kristjan Komlosi
7058512ee0 tidied comments, condensed UV calculation, removed redundant getA/B/I() 2020-04-24 16:49:09 +02:00
Kristjan Komlosi
325f1176c3 tidied translation tables 2020-04-24 16:47:43 +02:00
Kristjan Komlosi
0a9e610dd7 pruned import 2020-04-24 16:46:53 +02:00
Kristjan Komlosi
43b5277923 pipenv update 2020-04-24 16:46:27 +02:00
Kristjan Komlosi
5265ba9ae9 hotfix #2 2020-02-15 22:02:36 +01:00
Kristjan Komlosi
16e9c52194 rc.local hotfix 2020-02-15 21:59:41 +01:00
Kristjan Komlosi
c5db357cc0 fixed lighttpd root directory 2020-02-15 21:50:03 +01:00
Kristjan Komlosi
b7eb29f78b made rc.local executable 2020-02-15 21:46:12 +01:00
Kristjan Komlosi
1457655f16 GUI redesign 2020-02-15 15:56:28 +01:00
Kristjan Komlosi
a3f3558f7c fixed wavelength order in spectrogram 2020-02-14 14:18:38 +01:00
Kristjan Komlosi
bc72207187 fixed broken git headers 2019-11-18 17:19:18 +01:00
Kristjan Komlosi
7837f605cf Merge branch 'master' of github.com:cls-02/TeraHz 2019-11-17 22:23:28 +01:00
Kristjan Komlosi
3d1a925ba6 added school logo 2019-11-17 22:23:09 +01:00
Kristjan Komlosi
682fe20db2 added school logo 2019-11-17 22:21:54 +01:00
Kristjan Komlosi
949dd0bef2 Updated the main readme 2019-11-17 22:04:57 +01:00
Kristjan Komlosi
58cb777935 Documentation updates 2019-11-17 19:07:47 +01:00
18 changed files with 242 additions and 388 deletions

Binary file not shown.

View File

@@ -1,23 +1,37 @@
# TeraHz
[![Documentation Status](https://readthedocs.org/projects/terahz/badge/?version=latest)](https://terahz.readthedocs.io/en/latest/?badge=latest) [![Documentation Status](https://readthedocs.org/projects/terahz/badge/?version=latest)](https://terahz.readthedocs.io/en/latest/?badge=latest)
# <img alt="TeraHz logo" src="docs/imgs/logo-sq.png" width="200px"> TeraHz
*This project is currently at a standstill because SparkFUN stopped making one of the board this project needs. TeraHz will return in a better form some day!*
*Za slovensko različico se odpravite na <http://git.sckr-lab.tk/kristjank/TeraHz>*
TeraHz is a low-cost spectrometer based on a Raspberry Pi 3 or 3 B+ and three sensors: TeraHz is a low-cost portable spectrometer based on Raspberry Pi and a few
+ [__AS7265x__](https://www.tindie.com/products/onehorse/compact-as7265x-spectrometer/) commonly available sensor breakout boards. It's designed to bring low-cost
is a 18 channel spectrometer chipset that provides the device with spectral data scientific exploration of the light spectrum to educational institutions that
+ [__VEML6075__](https://www.sparkfun.com/products/15089) is an cannot afford the options available on the current market. It costs less than
UVA/UVB sensor 200€ with money to spare and uses only free, libre and open-source software
+ [__APDS-9301__](https://www.sparkfun.com/products/14350) is a calibrated illuminance (lux) meter that provides the device with reliable readings (FLOSS). It is free to use under the ISC license, a spiritual successor to the
classic 3-clause BSD license.
## Why? ## How to install
Because people and institutions could use an affordable and accurate light-analysing device that is also portable, easy to use and simple to assemble. TeraHz was started as an answer to our high school not being able to afford a commercially available solution. One TeraHz spectrometer costs around 150$ in parts, which makes it a competitive alternative to other solutions on the market today. Stable releases are available under the releases tab and can be installed either
by flashing a **preinstalled** ready to boot image with a stable version of
TeraHz preinstalled or by flashing a **preconfigured** image of DietPi and
installing TeraHz manually, which is useful if you want to test bleeding edge
releases. For more information, check out the [Build
guide](https://terahz.readthedocs.io/en/latest/build/).
## Docs
TeraHz usually works out of the box. A wireless network named `TeraHz_XXXXXX`
(XXXXXX = the last half of the MAC address) will appear. Password is
`terahertz`. After connection, open a web browser and visit `terahz.site`.
The UI will appear. To fetch data from the sensors, press the 'Get Data' button.
The readings are then plotted and written into the tables below the graph.
More documentation is available at <https://terahz.readthedocs.io>
## Development team ## Development team
Copyright 2018, 2019 - Kristjan Komloši (cls-02) - Project leader and main programmer
- Jakob Kosec (D3m1j4ck) - Frontend designer
- Juš Dolžan (ANormalPerson) - Math double-checker
- Kristjan "cls-02" Komloši (electronics, sensor drivers, backend) <img alt="TeraHz logo" src="http://www.sckr.si/documents/upload/konektor/logo/_SC.gif" width="200px">
- Jakob "D3m1j4ck" Kosec (frontend) TeraHz has been developed under guidance and financial support of Šolski Center Kranj (Kranj School Centre). Without their support, this project might have never been possible.
I would also like to thank Juš "ANormalPerson" Dolžan, who decided to leave the
team, but helped me a lot with backend development.

View File

@@ -1,17 +1,16 @@
# app.py - main backend program # app.py - main backend program
'''Main TeraHz backend program''' '''Main TeraHz backend program'''
# All code in this file is licensed under the ISC license, provided in LICENSE.txt # All code in this file is licensed under the ISC license, provided in LICENSE.txt
from flask import Flask from flask import Flask, jsonify
import flask
import sensors import sensors
app = Flask(__name__) app = Flask(__name__)
@app.route('/data') @app.route('/data')
def sendData(): def sendData():
'''Responder function for /data route''' '''Responder function for /data route'''
s = sensors.Spectrometer(path='/dev/serial0', baudrate=115200, tout=1) s = sensors.Spectrometer(path='/dev/serial0')
u = sensors.UVSensor() u = sensors.UVSensor()
l = sensors.LxMeter() l = sensors.LxMeter()
response = flask.jsonify([s.getData(), l.getData(), u.getABI()]) response = jsonify([s.getData(), l.getData(), u.getABI()])
response.headers.add('Access-Control-Allow-Origin', '*') response.headers.add('Access-Control-Allow-Origin', '*')
return response return response

Binary file not shown.

View File

@@ -6,8 +6,13 @@ import serial as ser
import pandas as pd import pandas as pd
import smbus2 import smbus2
class Spectrometer: class Spectrometer:
'''Class representing the AS7265X specrometer''' '''Class representing the AS7265X specrometer'''
def initializeSensor(self): def initializeSensor(self):
'''confirm the sensor is responding and proceed\ '''confirm the sensor is responding and proceed\
with spectrometer initialization''' with spectrometer initialization'''
@@ -23,8 +28,7 @@ class Spectrometer:
if rstring == 'ERROR': if rstring == 'ERROR':
raise Exception # sensor is in error state raise Exception # sensor is in error state
except: except:
raise Exception( raise Exception('No AT command response')
'An exception ocurred when performing spectrometer handshake')
def setParameters(self, parameters): def setParameters(self, parameters):
'''applies the parameters like LED light and gain to the spectrometer''' '''applies the parameters like LED light and gain to the spectrometer'''
@@ -53,8 +57,7 @@ class Spectrometer:
self.serialObject.write('ATLED3={}\n'.format(led).encode()) self.serialObject.write('ATLED3={}\n'.format(led).encode())
self.serialObject.readline() self.serialObject.readline()
except: except:
raise Exception( raise Exception('Error setting spectrometer parameters')
'An exception occured during spectrometer initialization')
def getData(self): def getData(self):
'''Returns spectral data in a pandas DataFrame.''' '''Returns spectral data in a pandas DataFrame.'''
@@ -62,11 +65,10 @@ class Spectrometer:
self.serialObject.write(b'ATCDATA\n') self.serialObject.write(b'ATCDATA\n')
rawresp = self.serialObject.readline().decode() rawresp = self.serialObject.readline().decode()
except: except:
raise Exception( raise Exception('Error polling spectrometer data')
'An exception occurred when polling for spectrometer data')
else: else:
responseorder = [i for i in 'RSTUVWGHIJKLABCDEF'] responseorder = list('RSTUVWGHIJKLABCDEF')
realorder = [i for i in 'ABCDEFGHRISJTUVWKL'] realorder = list('ABCDEFGHRISJTUVWKL')
response = pd.Series( response = pd.Series(
[float(i) / 35.0 for i in rawresp[:-3].split(',')], index=responseorder) [float(i) / 35.0 for i in rawresp[:-3].split(',')], index=responseorder)
return pd.DataFrame(response, index=realorder, columns=['uW/cm^2']).to_dict()['uW/cm^2'] return pd.DataFrame(response, index=realorder, columns=['uW/cm^2']).to_dict()['uW/cm^2']
@@ -78,14 +80,14 @@ class Spectrometer:
try: try:
self.serialObject = ser.Serial(path, baudrate, timeout=tout) self.serialObject = ser.Serial(path, baudrate, timeout=tout)
except: except:
raise Exception( raise Exception('Error opening serial port: {}'.format(path))
'An exception occured when opening the serial port at {}'.format(path))
else: else:
self.initializeSensor() self.initializeSensor()
class LxMeter: class LxMeter:
'''Class representing the APDS-9301 digital photometer.''' '''Class representing the APDS-9301 digital photometer.'''
def __init__(self, busNumber=1, addr=0x39): def __init__(self, busNumber=1, addr=0x39):
self.addr = addr self.addr = addr
try: try:
@@ -93,14 +95,14 @@ class LxMeter:
self.bus = smbus2.SMBus(busNumber) self.bus = smbus2.SMBus(busNumber)
except: except:
raise Exception( raise Exception(
'An exception occured opening the SMBus {}'.format(self.bus)) 'Error opening SMBus {}'.format(self.bus))
try: try:
self.bus.write_byte_data( self.bus.write_byte_data(
self.addr, 0xa0, 0x03) # enable the sensor self.addr, 0xa0, 0x03) # enable the sensor
self.setGain(16) self.setGain(16)
except: except:
raise Exception('An exception occured when enabling lux meter') raise Exception('Error enabling lux meter')
def setGain(self, gain): def setGain(self, gain):
'''Set the sensor gain. Either 1 or 16.''' '''Set the sensor gain. Either 1 or 16.'''
@@ -109,15 +111,13 @@ class LxMeter:
temp = self.bus.read_byte_data(self.addr, 0xa1) temp = self.bus.read_byte_data(self.addr, 0xa1)
self.bus.write_byte_data(self.addr, 0xa1, 0xef & temp) self.bus.write_byte_data(self.addr, 0xa1, 0xef & temp)
except: except:
raise Exception( raise Exception('Error setting lux meter gain')
'An exception occured when setting lux meter gain')
if gain == 16: if gain == 16:
try: try:
temp = self.bus.read_byte_data(self.addr, 0xa1) temp = self.bus.read_byte_data(self.addr, 0xa1)
self.bus.write_byte_data(self.addr, 0xa1, 0x10 | temp) self.bus.write_byte_data(self.addr, 0xa1, 0x10 | temp)
except: except:
raise Exception( raise Exception('Error setting lux meter gain')
'An exception occured when setting lux meter gain')
else: else:
raise Exception('Invalid gain') raise Exception('Invalid gain')
@@ -160,7 +160,7 @@ class LxMeter:
except: except:
raise Exception('An exception occured fetching lux channels') raise Exception('An exception occured fetching lux channels')
# scary computations ahead! refer to the apds-9301 datasheet! # Refer to APDS-9301 datasheet!
if chB / chA <= 0.5 and chB / chA > 0: if chB / chA <= 0.5 and chB / chA > 0:
lux = 0.0304 * chA - 0.062 * chA * (chB / chA)**1.4 lux = 0.0304 * chA - 0.062 * chA * (chB / chA)**1.4
elif chB / chA <= 0.61 and chB / chA > 0.5: elif chB / chA <= 0.61 and chB / chA > 0.5:
@@ -176,6 +176,7 @@ class LxMeter:
class UVSensor: class UVSensor:
'''Class representing VEML6075 UVA/B meter''' '''Class representing VEML6075 UVA/B meter'''
def __init__(self, bus=1, addr=0x10): def __init__(self, bus=1, addr=0x10):
self.addr = addr self.addr = addr
try: try:
@@ -187,9 +188,16 @@ class UVSensor:
try: try:
# enable the sensor and set the integration time # enable the sensor and set the integration time
self.bus.write_byte_data(self.addr, 0x00, 0b00010000) self.bus.write_byte_data(self.addr, 0x00, 0b00010000)
# trigger a measurement to prevent bus errors at first read
self.bus.write_byte_data(self.addr, 0x00, 0b00010010) # UV_AF=1
self.bus.write_byte_data(self.addr, 0x00, 0b00010110) # UV_TRIG=1
self.bus.write_byte_data(
self.addr, 0x00, 0b00010000) # normal mode
except: except:
raise Exception( raise Exception(
'An exception occured when initalizing the UV Sensor') 'Error initalizing the UV Sensor')
def getABI(self): def getABI(self):
'''Calculates the UVA and UVB irradiances, '''Calculates the UVA and UVB irradiances,
@@ -202,40 +210,16 @@ class UVSensor:
c1 = self.bus.read_word_data(self.addr, 0x0a) c1 = self.bus.read_word_data(self.addr, 0x0a)
c2 = self.bus.read_word_data(self.addr, 0x0b) c2 = self.bus.read_word_data(self.addr, 0x0b)
except: except:
raise Exception('An exception occured when fetching raw UV data') raise Exception('Error fetching raw UV data')
# scary computations ahead! refer to Vishay app note 84339 and Sparkfun # Refer to Vishay app note 84339 and Sparkfun VEML6075 documentation.
# VEML6075 documentation. # The computed values may be negative if UV is vastly weaker than
# visible and IR light. This is not a bug!
# compensate for visible and IR noise
aCorr = aRaw - 2.22 * c1 - 1.33 * c2
bCorr = bRaw - 2.95 * c1 - 1.74 * c2
# convert values into irradiances
a = aCorr * 1.06
b = bCorr * 0.48
# zero out negative results (readings with no uv)
if a < 0:
a = 0
if b < 0:
b = 0
# last, calculate the UV index
i = (a + b) / 2
a = (aRaw - 2.22 * c1 - 1.33 * c2) * 1.06
b = (bRaw - 2.95 * c1 - 1.74 * c2) * 0.48
i = (a + b) / 2 # calculate UV index
return [a, b, i] return [a, b, i]
def getA(self):
'''Returns UVA value. A getABI() wrapper.'''
return self.getABI()[0]
def getB(self):
'''Returns UVB value. A getABI() wrapper.'''
return self.getABI()[1]
def getI(self):
'''Returns UV index. A getABI() wrapper.'''
return self.getABI()[2]
def on(self): def on(self):
'''Turns the UV sensor on after shutdown.''' '''Turns the UV sensor on after shutdown.'''
try: try:
@@ -244,7 +228,7 @@ class UVSensor:
self.bus.write_byte_data(self.addr, 0x00, 0x10) self.bus.write_byte_data(self.addr, 0x00, 0x10)
except: except:
raise Exception( raise Exception(
'An exception occured when turning the UV sensor on') 'Error turning the UV sensor on')
def off(self): def off(self):
'''Shuts the UV sensor down.''' '''Shuts the UV sensor down.'''
@@ -254,4 +238,4 @@ class UVSensor:
self.bus.write_byte_data(self.addr, 0x00, 0x11) self.bus.write_byte_data(self.addr, 0x00, 0x11)
except: except:
raise Exception( raise Exception(
'An exception occured when shutting the UV sensor down') 'Error shutting the UV sensor down')

View File

@@ -1,37 +0,0 @@
# storage.py - storage backend for TeraHz
'''TeraHz storage backend'''
# Copyright Kristjan Komloši 2019
# All code in this file is licensed under the ISC license,
# provided in LICENSE.txt
import sqlite3
class jsonStorage:
'''Class for simple sqlite3 database of JSON entries'''
def __init__(self, dbFile):
'''Storage object constructor. Argument is filename'''
self.db = sqlite3.connect(dbFile)
def listJSONs(self):
'''Returns a list of all existing entries.'''
c = self.db.cursor()
c.execute('SELECT * FROM storage')
result = c.fetchall()
c.close()
return result
def storeJSON(self, jsonString, comment):
'''Stores a JSON entry along with a timestamp and a comment.'''
c = self.db.cursor()
c.execute(('INSERT INTO storage VALUES (datetime'
'(\'now\', \'localtime\'), ?, ?)'), (comment, jsonString))
c.close()
self.db.commit()
def retrieveJSON(self, timestamp):
'''Retrieves a JSON entry. Takes a timestamp string'''
c = self.db.cursor()
c.execute('SELECT * FROM storage WHERE timestamp = ?', (timestamp,))
result = c.fetchall()
c.close()
return result

View File

@@ -1,7 +0,0 @@
#!/usr/bin/python3
# Minimal flup configuration for Flask
from flup.server.fcgi import WSGIServer
from app import app
if __name__ == '__main__':
WSGIServer(app, bindAddress='/var/www/api/terahz.sock').run()

View File

@@ -7,17 +7,12 @@ TeraHz was developed on and for the Raspberry Pi 3 Model B+. Compatibility with
other Raspberries can probably be achieved by tweaking the device paths in the other Raspberries can probably be achieved by tweaking the device paths in the
`app.py` file, but isn't confirmed at this point. Theoretically, 3 Model B and `app.py` file, but isn't confirmed at this point. Theoretically, 3 Model B and
Zero W should work out of the box, but models without Wi-Fi will need an Zero W should work out of the box, but models without Wi-Fi will need an
external Wi-Fi adapter if Wi-Fi functionality is desired. The practicality of external Wi-Fi adapter if Wi-Fi functionality is desired.
compiling Python on the first generation of Raspberry Pis is also very
questionable.
Sensors required for operation are: TeraHz depends on three separate sensor boards:
- AS7265x - AS7265x spectral chipset
- VEML6075 - VEML6075 UV sensor
- APDS-9301 - APDS-9301 lux-meter
They provide the spectrometry data, UV data and illuminance data, respectively.
They all support I2C, AS7265x supports UART in addition.
The sensors leech power from the GPIO connector, thus eliminating the need for a The sensors leech power from the GPIO connector, thus eliminating the need for a
separate power supply. The necessary power for the whole system is delivered through separate power supply. The necessary power for the whole system is delivered through

View File

@@ -1,4 +1,4 @@
# install.sh - install TeraHz onto a Raspbian or DietPi installation # install.sh - install TeraHz onto a Raspbian Lite instance
cd `dirname $0` cd `dirname $0`
apt -y update apt -y update
@@ -6,13 +6,16 @@ apt -y full-upgrade
apt install -y python3 python3-pip lighttpd dnsmasq hostapd libatlas-base-dev apt install -y python3 python3-pip lighttpd dnsmasq hostapd libatlas-base-dev
pip3 install numpy pandas flask smbus2 pyserial gunicorn pip3 install numpy pandas flask smbus2 pyserial gunicorn
cp -R hostapd/ /etc cp -R hostapd/* /etc/hostapd/
chmod +rx /etc/hostapd/edit_ssid.sh chmod +rx /etc/hostapd/edit_ssid.sh
cp dnsmasq.conf /etc cp dnsmasq.conf /etc/
cp rc.local /etc
cp rc.local /etc/
chmod +rx /etc/rc.local
cp interfaces-terahz /etc/network/interfaces.d/ cp interfaces-terahz /etc/network/interfaces.d/
cp -R ../frontend/* /var/www/html cp -R ../frontend/* /var/www/html/
mkdir -p /usr/local/lib/terahz mkdir -p /usr/local/lib/terahz
cp -R ../backend/* /usr/local/lib/terahz cp -R ../backend/* /usr/local/lib/terahz

View File

@@ -1,27 +0,0 @@
server.modules = (
"mod_access",
"mod_alias",
"mod_compress",
"mod_redirect"
)
server.document-root = "/var/www/html"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/var/run/lighttpd.pid"
server.username = "www-data"
server.groupname = "www-data"
server.port = 80
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
url.access-deny = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
compress.cache-dir = "/var/cache/lighttpd/compress/"
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )
# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"

0
etcs/rc.local Normal file → Executable file
View File

View File

@@ -1,7 +1,5 @@
// All code in this file is licensed under the ISC license, provided in LICENSE.txt // All code in this file is licensed under the ISC license, provided in LICENSE.txt
$('#update').click(function () { $('#update').click(updateData);
updateData();
});
// jQuery event binder // jQuery event binder
function updateData () { function updateData () {
@@ -22,14 +20,14 @@ function graphSpectralData (obj, dom) {
var graphPoints = []; var graphPoints = [];
var graphXTicks = []; var graphXTicks = [];
Object.keys(obj).forEach((element, index) => { const specter = 'ABCDEFGHRISJTUVWKL';
graphPoints.push([index, obj[element]]); // build array of points for (var i = 0; i < specter.length; i++) {
graphXTicks.push([index, element]); // build array of axis labels graphPoints.push([i, obj[specter[i]]]);
}); graphXTicks.push([i, specter[i]]);
// console.log(graphPoints); }
const options = { const options = {
grid: {color: 'white'}, grid: { color: 'white' },
xaxis: {ticks: graphXTicks} xaxis: { ticks: graphXTicks }
}; };
$.plot('#graph', [graphPoints], options); $.plot('#graph', [graphPoints], options);
// flot expects an array of arrays (lines) of 2-element arrays (points) // flot expects an array of arrays (lines) of 2-element arrays (points)

View File

@@ -6,146 +6,6 @@
<link rel="stylesheet" href="lib/bootstrap.min.css"> <link rel="stylesheet" href="lib/bootstrap.min.css">
<link rel="stylesheet" href="stylesheet.css"> <link rel="stylesheet" href="stylesheet.css">
<title>TeraHz</title> <title>TeraHz</title>
</head>
<body>
<div class="container text-center">
<h1><img src="lib/logo-sq.png" height="64px">TeraHz</h1>
</div>
<div class="container">
<button id="update" class="btn btn-primary m-1 float-right">Get data</button>
<p id="debug">
</p>
<h3>Spectrogram</h3>
<div id="graph" style="height:480px;width:720px"></div>
<h3>Spectral readings</h3>
<table class="table table-dark table-sm" id="specter">
<thead class="thead-dark">
<tr>
<th>Band</th>
<th>Wavelength [nm]</th>
<th>Irradiance [μW/cm²]</th>
</tr>
</thead>
<tr>
<td>A</td>
<td>410 nm</td>
<td id="A">---</td>
</tr>
<tr>
<td>B</td>
<td>435 nm</td>
<td id="B">---</td>
</tr>
<tr>
<td>C</td>
<td>460 nm</td>
<td id="C">---</td>
</tr>
<tr>
<td>D</td>
<td>485 nm</td>
<td id="D">---</td>
</tr>
<tr>
<td>E</td>
<td>510 nm</td>
<td id="E">---</td>
</tr>
<tr>
<td>F</td>
<td>535 nm</td>
<td id="F">---</td>
</tr>
<tr>
<td>G</td>
<td>560 nm</td>
<td id="G">---</td>
</tr>
<tr>
<td>H</td>
<td>585 nm</td>
<td id="H">---</td>
</tr>
<tr>
<td>R</td>
<td>610 nm</td>
<td id="R">---</td>
</tr>
<tr>
<td>I</td>
<td>645 nm</td>
<td id="I">---</td>
</tr>
<tr>
<td>S</td>
<td>680 nm</td>
<td id="S">---</td>
</tr>
<tr>
<td>J</td>
<td>705 nm</td>
<td id="J">---</td>
</tr>
<tr>
<td>T</td>
<td>730 nm</td>
<td id="T">---</td>
</tr>
<tr>
<td>U</td>
<td>760 nm</td>
<td id="U">---</td>
</tr>
<tr class="table-secondary">
<td>V</td>
<td>810 nm</td>
<td id="V">---</td>
</tr>
<tr class="table-secondary">
<td>W</td>
<td>860 nm</td>
<td id="W">---</td>
</tr>
<tr class="table-secondary">
<td>K</td>
<td>900 nm</td>
<td id="K">---</td>
</tr>
<tr class="table-secondary">
<td>L</td>
<td>940 nm</td>
<td id="L">---</td>
</tr>
</table>
<br>
<h3>Lux and UV readings</h3>
<table class="table-dark table" id="luxuv">
<thead class="thead-dark">
<tr>
<th>Parameter</th>
<th>Value</th>
</tr>
</thead>
<tr>
<td>Illuminance [lx]</td>
<td id="lx">---</td>
</tr>
<tr>
<td>UVA irradiance [μW/cm²]</td>
<td id="uva">---</td>
</tr>
<tr>
<td>UVB irradiance [μW/cm²]</td>
<td id="uvb">---</td>
</tr>
<tr>
<td>UVA/UVB average [μW/cm²]</td>
<td id="uvi">---</td>
</tr>
</table>
</div>
<script src="lib/bootstrap.bundle.min.js"></script> <script src="lib/bootstrap.bundle.min.js"></script>
<script src="lib/jquery-3.4.1.min.js"></script> <script src="lib/jquery-3.4.1.min.js"></script>
<script src="lib/flot/jquery.flot.js"></script> <script src="lib/flot/jquery.flot.js"></script>
@@ -157,6 +17,157 @@
<script src="lib/flot/jquery.flot.browser.js"></script> <script src="lib/flot/jquery.flot.browser.js"></script>
<script src="lib/flot/jquery.flot.drawSeries.js"></script> <script src="lib/flot/jquery.flot.drawSeries.js"></script>
<script src="lib/flot/jquery.flot.uiConstants.js"></script> <script src="lib/flot/jquery.flot.uiConstants.js"></script>
</body> </head>
<body>
<div class="container text-center">
<h1><img src="lib/logo-sq.png" height="64px">TeraHz</h1>
</div>
<div class="container">
<button id="update" onclick="updateData()" class="btn btn-primary">Get data</button>
<!-- <button id="download" class="btn btn-primary">Download</button>
<button id="debug" class="btn btn-danger">DEBUG</button> -->
</div>
<div class="container">
<div class="row">
<div class="col-sm">
<h4>Spectrogram</h4>
<div id="graph" style="height:480px;width:720px"></div>
</div>
<div class="col-sm">
<h4>Visible+IR spectrum</h4>
<table class="table table-dark table-sm" id="specter">
<thead class="thead-dark">
<tr>
<th>Band</th>
<th>Wavelength [nm]</th>
<th>Irradiance [μW/cm²]</th>
</tr>
</thead>
<tr>
<td>A</td>
<td>410 nm</td>
<td id="A">---</td>
</tr>
<tr>
<td>B</td>
<td>435 nm</td>
<td id="B">---</td>
</tr>
<tr>
<td>C</td>
<td>460 nm</td>
<td id="C">---</td>
</tr>
<tr>
<td>D</td>
<td>485 nm</td>
<td id="D">---</td>
</tr>
<tr>
<td>E</td>
<td>510 nm</td>
<td id="E">---</td>
</tr>
<tr>
<td>F</td>
<td>535 nm</td>
<td id="F">---</td>
</tr>
<tr>
<td>G</td>
<td>560 nm</td>
<td id="G">---</td>
</tr>
<tr>
<td>H</td>
<td>585 nm</td>
<td id="H">---</td>
</tr>
<tr>
<td>R</td>
<td>610 nm</td>
<td id="R">---</td>
</tr>
<tr>
<td>I</td>
<td>645 nm</td>
<td id="I">---</td>
</tr>
<tr>
<td>S</td>
<td>680 nm</td>
<td id="S">---</td>
</tr>
<tr>
<td>J</td>
<td>705 nm</td>
<td id="J">---</td>
</tr>
<tr>
<td>T</td>
<td>730 nm</td>
<td id="T">---</td>
</tr>
<tr>
<td>U</td>
<td>760 nm</td>
<td id="U">---</td>
</tr>
<tr class="table-secondary">
<td>V</td>
<td>810 nm</td>
<td id="V">---</td>
</tr>
<tr class="table-secondary">
<td>W</td>
<td>860 nm</td>
<td id="W">---</td>
</tr>
<tr class="table-secondary">
<td>K</td>
<td>900 nm</td>
<td id="K">---</td>
</tr>
<tr class="table-secondary">
<td>L</td>
<td>940 nm</td>
<td id="L">---</td>
</tr>
</table>
</div>
<div class="col-sm">
<h4>UV+Illuminance</h4>
<table class="table-dark table table-sm" id="luxuv">
<thead class="thead-dark">
<tr>
<th>Parameter</th>
<th>Value</th>
</tr>
</thead>
<tr>
<td>Illuminance [lx]</td>
<td id="lx">---</td>
</tr>
<tr>
<td>UVA irradiance [μW/cm²]</td>
<td id="uva">---</td>
</tr>
<tr>
<td>UVB irradiance [μW/cm²]</td>
<td id="uvb">---</td>
</tr>
<tr>
<td>UVA/UVB average [μW/cm²]</td>
<td id="uvi">---</td>
</tr>
</table>
</div>
</div>
</div>
</body>
</html> </html>

View File

@@ -1,45 +0,0 @@
# getcdata.py - fetch the calibrated data from the AS7265x module
# All code in this file is licensed under the ISC license, provided in LICENSE.txt
import serial as ser
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time
#global variables
uartpath = '/dev/ttyUSB0'
uartbaud = 115200
uarttout = 5
wl = [410, 435, 460, 485, 510, 535, 560, 585, 610, 645, 680, 705, 730, 760, 810, 860, 900, 940]
responseorder = [i for i in 'RSTUVWGHIJKLABCDEF'] # works, do NOT touch!
realorder = [i for i in 'ABCDEFGHRISJTUVWKL']
print('getcdata')
print('This utility is part of the TeraHz project')
wavelens = pd.Series(realorder)
plt.ion()
win = plt.figure()
spectrum=win.add_subplot(111)
with ser.Serial(uartpath, uartbaud, timeout=uarttout) as sensor:
while True:
sensor.write(b'ATCDATA\n')
rawresp = sensor.readline().decode()
# parses, calculates and saves the data
response = pd.Series([float(i)/35.0 for i in rawresp[:-3].split(',')], index=responseorder)
data = pd.DataFrame(response, index=realorder, columns = ['uW/cm^2']) # puts data into a DataFrame
data.insert(0, 'wavelenght', wl) #inserts a legend
print(data)
spectrum.cla()
spectrum.plot(data['wavelenght'], data['uW/cm^2'])
spectrum.set_xlabel('Valovna dolžina')
spectrum.set_ylabel('uW/cm2')
win.canvas.draw()
time.sleep(0.1)

View File

@@ -1,12 +0,0 @@
import smbus2
bus = smbus2.SMBus(1)
result = bus.read_byte_data(0x39, 0x8a)
print('LUX Meter ID = {}'.format(result))
result = bus.read_word_data(0x10, 0x0c)
print('UV sensor ID = {}'.format(result))
result = bus.read_word_data(0x39, 0xec)
print('LUX chan 0 = {}'.format(result))

View File

@@ -1,22 +0,0 @@
from serial import Serial
import tkinter as tk
import pandas as pd
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
uartpath = '/dev/ttyUSB0'
uartbaud = 115200
uarttout = 5
wl = [410, 435, 460, 485, 510, 535, 560, 585, 610, 645, 680, 705, 730, 760, 810, 860, 900, 940]
responseorder = [i for i in 'RSTUVWGHIJKLABCDEF'] # works, do NOT touch!
realorder = [i for i in 'ABCDEFGHRISJTUVWKL']
root = tk.Tk()
root.wm_title('TeraHz Demo')
fig = Figure(figsize=(5, 4), dpi=100)
plot = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig, master=root)