Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1dc9fecff6 | ||
|
|
57d10a5ae5
|
||
|
|
2cc0fd977b | ||
|
|
3d3254c4a7 | ||
|
|
cfe6e3c286 | ||
|
|
7a3877b34b | ||
|
|
f20dd30292 | ||
|
|
ef5c87d8d2 | ||
|
|
4878df9ca8 |
BIN
..gitignore.swp
BIN
..gitignore.swp
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
[](https://terahz.readthedocs.io/en/latest/?badge=latest)
|
[](https://terahz.readthedocs.io/en/latest/?badge=latest)
|
||||||
# <img alt="TeraHz logo" src="docs/imgs/logo-sq.png" width="200px"> TeraHz
|
# <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>*
|
*Za slovensko različico se odpravite na <http://git.sckr-lab.tk/kristjank/TeraHz>*
|
||||||
|
|
||||||
TeraHz is a low-cost portable spectrometer based on Raspberry Pi and a few
|
TeraHz is a low-cost portable spectrometer based on Raspberry Pi and a few
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ 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 = jsonify([s.getData(), l.getData(), u.getABI()])
|
response = jsonify([s.getData(), l.getData(), u.getABI()])
|
||||||
|
|||||||
Binary file not shown.
@@ -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,8 +65,7 @@ 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 = list('RSTUVWGHIJKLABCDEF')
|
responseorder = list('RSTUVWGHIJKLABCDEF')
|
||||||
realorder = list('ABCDEFGHRISJTUVWKL')
|
realorder = list('ABCDEFGHRISJTUVWKL')
|
||||||
@@ -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')
|
||||||
|
|
||||||
@@ -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:
|
||||||
@@ -189,13 +190,14 @@ class UVSensor:
|
|||||||
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
|
# 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, 0b00010010) # UV_AF=1
|
||||||
self.bus.write_byte_data(self.addr, 0x00, 0b00010110) # UV_TRIG=1
|
self.bus.write_byte_data(self.addr, 0x00, 0b00010110) # UV_TRIG=1
|
||||||
self.bus.write_byte_data(self.addr, 0x00, 0b00010000) # normal mode
|
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,
|
||||||
@@ -208,14 +210,14 @@ 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')
|
||||||
# Refer to Vishay app note 84339 and Sparkfun VEML6075 documentation.
|
# Refer to Vishay app note 84339 and Sparkfun VEML6075 documentation.
|
||||||
# The computed values may be negative if UV is vastly weaker than
|
# The computed values may be negative if UV is vastly weaker than
|
||||||
# visible and IR light. This is not a bug!
|
# visible and IR light. This is not a bug!
|
||||||
|
|
||||||
a = (aRaw - 2.22 * c1 - 1.33 * c2) * 1.06
|
a = (aRaw - 2.22 * c1 - 1.33 * c2) * 1.06
|
||||||
b = (bRaw - 2.95 * c1 - 1.74 * c2) * 0.48
|
b = (bRaw - 2.95 * c1 - 1.74 * c2) * 0.48
|
||||||
i = (a + b) / 2 # calculate UV index
|
i = (a + b) / 2 # calculate UV index
|
||||||
return [a, b, i]
|
return [a, b, i]
|
||||||
|
|
||||||
def on(self):
|
def on(self):
|
||||||
@@ -226,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.'''
|
||||||
@@ -236,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')
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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()
|
|
||||||
@@ -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,15 +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
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,8 @@
|
|||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<button id="update" onclick="updateData()" class="btn btn-primary">Get data</button>
|
<button id="update" onclick="updateData()" class="btn btn-primary">Get data</button>
|
||||||
<button id="download" class="btn btn-primary">Download</button>
|
<!-- <button id="download" class="btn btn-primary">Download</button>
|
||||||
<button id="debug" class="btn btn-danger">DEBUG</button>
|
<button id="debug" class="btn btn-danger">DEBUG</button> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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))
|
|
||||||
@@ -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)
|
|
||||||
Reference in New Issue
Block a user