web
This commit is contained in:
parent
fc516343ed
commit
ed5c03ffec
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 63 KiB |
@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
Seven-channel multiple thermocouple reader and logger HAT for the Raspberry Pi.
|
Seven-channel multiple thermocouple reader and logger HAT for the Raspberry Pi.
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
This software supports the following thermocouple types:
|
This software supports the following thermocouple types:
|
||||||
|
|
||||||
- B
|
- B
|
||||||
- E
|
- E
|
||||||
- J
|
- J
|
||||||
@ -15,6 +14,7 @@ This software supports the following thermocouple types:
|
|||||||
- T
|
- T
|
||||||
|
|
||||||
Features not yet implemented but planned:
|
Features not yet implemented but planned:
|
||||||
|
|
||||||
- More database logging options than SQLite3
|
- More database logging options than SQLite3
|
||||||
- Advanced filtering, incl. user-selectable filtering stages and sample sizes
|
- Advanced filtering, incl. user-selectable filtering stages and sample sizes
|
||||||
- Several logging options at once, one local, one or more remote
|
- Several logging options at once, one local, one or more remote
|
||||||
@ -24,5 +24,6 @@ Features not yet implemented but planned:
|
|||||||
- Request dumps from filter stages for noise study
|
- Request dumps from filter stages for noise study
|
||||||
- ... and more!
|
- ... and more!
|
||||||
|
|
||||||
|
|
||||||
Note: Most thermocouples that have a coloured and a white lead, usually have the coloured one as the positive.
|
Note: Most thermocouples that have a coloured and a white lead, usually have the coloured one as the positive.
|
||||||
|
|
||||||
|

|
||||||
|
@ -25,9 +25,11 @@ filter.samples = 20
|
|||||||
|
|
||||||
[Channel_3]
|
[Channel_3]
|
||||||
type = 'T'
|
type = 'T'
|
||||||
|
gain = 112.28821
|
||||||
|
|
||||||
[Channel_4]
|
[Channel_4]
|
||||||
type = 'K'
|
type = 'K'
|
||||||
|
gain = 2.8129883e2
|
||||||
|
|
||||||
[Channel_6]
|
[Channel_6]
|
||||||
type = 'J'
|
type = 'J'
|
||||||
|
10
main.go
10
main.go
@ -28,29 +28,29 @@ func main() {
|
|||||||
syscall.SIGHUP,
|
syscall.SIGHUP,
|
||||||
syscall.SIGQUIT)
|
syscall.SIGQUIT)
|
||||||
|
|
||||||
config, err := config.Load()
|
cfg, err := config.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error loading config: %v", err)
|
log.Fatalf("Error loading config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pcbPort, err = pcb.NewAdapter(config)
|
pcbPort, err = pcb.NewAdapter(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Fatal error: %v\n", err)
|
log.Fatalf("Fatal error: %v\n", err)
|
||||||
}
|
}
|
||||||
defer pcbPort.Deinit()
|
defer pcbPort.Deinit()
|
||||||
|
|
||||||
corePort, err = core.NewAdapter(pcbPort, config)
|
corePort, err = core.NewAdapter(pcbPort, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error starting TH7 Adapter: %v\n", err)
|
log.Fatalf("Error starting TH7 Adapter: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dbPort, err = db.NewAdapter(corePort, config)
|
dbPort, err = db.NewAdapter(corePort, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Fatal error: %v\n", err)
|
log.Fatalf("Fatal error: %v\n", err)
|
||||||
}
|
}
|
||||||
defer dbPort.Close()
|
defer dbPort.Close()
|
||||||
|
|
||||||
webPort = web.NewGinAdapter(corePort, config.Board.Port)
|
webPort = web.NewGinAdapter(corePort, cfg)
|
||||||
go webPort.Run()
|
go webPort.Run()
|
||||||
|
|
||||||
sig := <-kill
|
sig := <-kill
|
||||||
|
@ -1,34 +1,91 @@
|
|||||||
const vdd = document.getElementById('vdd');
|
const thermocoupleTypeTable = ["uV", "B", "E", "J", "K", "N", "R", "S", "T"];
|
||||||
const vref = document.getElementById('vref');
|
|
||||||
const vadj = document.getElementById('vadj');
|
|
||||||
const ts = document.getElementById('timestamp');
|
|
||||||
const table = document.getElementById('data');
|
|
||||||
|
|
||||||
let old_channel_count=0;
|
const elements = {
|
||||||
|
read: {
|
||||||
|
vdd: document.getElementById("vdd"),
|
||||||
|
vref: document.getElementById("vref"),
|
||||||
|
vadj: document.getElementById("vadj"),
|
||||||
|
ts: document.getElementById("timestamp"),
|
||||||
|
table: document.getElementById("data"),
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
table: document.getElementById("thermocouple"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
async function update () {
|
let readOldChannelCount = 0;
|
||||||
|
let configOldChannelCount = 0;
|
||||||
|
|
||||||
data = await fetch("/data").then((data)=>{return data.json()});
|
async function fetchData(url) {
|
||||||
vdd.innerHTML = "V<sub>DD</sub>: " + parseFloat(data["ratio"]["pivdd"]);
|
const response = await fetch(url);
|
||||||
vref.innerHTML = "V<sub>REF</sub>: " + parseFloat(data["ratio"]["vref"]);
|
return response.json();
|
||||||
vadj.innerHTML = "V<sub>ADJ</sub>: " + parseFloat(data["ratio"]["vadj"]);
|
|
||||||
ts.innerHTML = "Last updated: " + data["time"];
|
|
||||||
for (let i=0; i<old_channel_count; i++) {
|
|
||||||
table.deleteRow(-1);
|
|
||||||
}
|
}
|
||||||
old_channel_count =0;
|
|
||||||
|
|
||||||
data["channels"].forEach(e => {
|
function clearTableBody(tableType) {
|
||||||
let unit = e["unit"];
|
const table = elements[tableType].table;
|
||||||
let value = e["value"];
|
const tbody = table.querySelector("tbody");
|
||||||
let channel = e["id"];
|
|
||||||
|
|
||||||
let row = table.insertRow(-1);
|
if (tbody) {
|
||||||
row.insertCell(0).innerText = channel;
|
tbody.innerHTML = "";
|
||||||
row.insertCell(1).innerText = value;
|
} else {
|
||||||
row.insertCell(2).innerText = unit;
|
// If tbody doesn't exist, recreate it
|
||||||
old_channel_count++;
|
const newTbody = document.createElement("tbody");
|
||||||
|
table.appendChild(newTbody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTable(data, tableType, oldChannelCount, updateFunction) {
|
||||||
|
clearTableBody(tableType);
|
||||||
|
|
||||||
|
oldChannelCount = 0;
|
||||||
|
|
||||||
|
data.channels.forEach((channel) => {
|
||||||
|
updateFunction(channel, tableType);
|
||||||
|
oldChannelCount++;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
update();
|
|
||||||
setInterval(update, 1000);
|
function updateReadTable(channel, tableType) {
|
||||||
|
const { value, id } = channel;
|
||||||
|
|
||||||
|
const row = elements[tableType].table.querySelector("tbody").insertRow(-1);
|
||||||
|
row.insertCell(0).innerText = id;
|
||||||
|
row.insertCell(1).innerText = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateConfigTable(channel, tableType) {
|
||||||
|
const { id, thermocouple, gain, offset, filter } = channel;
|
||||||
|
|
||||||
|
const row = elements[tableType].table.querySelector("tbody").insertRow(-1);
|
||||||
|
row.insertCell(0).innerText = id;
|
||||||
|
row.insertCell(1).innerText = thermocoupleTypeTable[thermocouple];
|
||||||
|
row.insertCell(2).innerText = gain;
|
||||||
|
row.insertCell(3).innerText = offset;
|
||||||
|
row.insertCell(4).innerText = filter.sample_size;
|
||||||
|
row.insertCell(5).innerText = filter.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateOthers(data) {
|
||||||
|
const { ratio, time } = data;
|
||||||
|
elements.read.ts.innerText = time;
|
||||||
|
elements.read.vref.innerHTML = `V<sub>REF</sub>: ${ratio.vref}`;
|
||||||
|
elements.read.vadj.innerHTML = `V<sub>ADJ</sub>: ${ratio.vadj}`;
|
||||||
|
elements.read.vdd.innerHTML = `V<sub>DD</sub>: ${ratio.pivdd}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateRead() {
|
||||||
|
const data = await fetchData("/data");
|
||||||
|
updateTable(data, "read", readOldChannelCount, updateReadTable);
|
||||||
|
updateOthers(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateConfig() {
|
||||||
|
const data = await fetchData("/config");
|
||||||
|
updateTable(data.config, "config", configOldChannelCount, updateConfigTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRead();
|
||||||
|
updateConfig();
|
||||||
|
|
||||||
|
setInterval(updateRead, 1000);
|
||||||
|
setInterval(updateConfig, 5000);
|
||||||
|
@ -6,22 +6,87 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{.title}}</title>
|
<title>{{.title}}</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
margin: 20px;
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#vdd, #vref, #vadj, #timestamp {
|
||||||
|
margin-top: 20px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
#thermocouple {
|
||||||
|
margin-top: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#thermocouple td {
|
||||||
|
min-width: 6rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>TH7</h1>
|
<h1>TH7</h1>
|
||||||
|
|
||||||
<table id="data">
|
<table id="data">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Channel</th>
|
<th>Channel</th>
|
||||||
<th>Value</th>
|
<th>Value</th>
|
||||||
<th>Unit</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p id="vdd">V<sub>DD</sub>:</p>
|
<p id="vdd">V<sub>DD</sub>:</p>
|
||||||
<p id="vref">V<sub>REF</sub>:</p>
|
<p id="vref">V<sub>REF</sub>:</p>
|
||||||
<p id="vadj">V<sub>ADJ</sub>:</p>
|
<p id="vadj">V<sub>ADJ</sub>:</p>
|
||||||
<p id="timestamp">Last updated:</p>
|
<p id="timestamp">Last updated:</p>
|
||||||
|
|
||||||
|
<h2>Thermocouple config</h2>
|
||||||
|
|
||||||
|
<table id="thermocouple">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Channel</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Gain</th>
|
||||||
|
<th>Offset</th>
|
||||||
|
<th>Filter size</th>
|
||||||
|
<th>Filter type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
|
||||||
<script src="/assets/data-updater.js"></script>
|
<script src="/assets/data-updater.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
14
web/gin.go
14
web/gin.go
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"th7/data/config"
|
||||||
"th7/data/core"
|
"th7/data/core"
|
||||||
"th7/ports"
|
"th7/ports"
|
||||||
)
|
)
|
||||||
@ -15,6 +16,7 @@ import (
|
|||||||
type GinAdapter struct {
|
type GinAdapter struct {
|
||||||
router *gin.Engine
|
router *gin.Engine
|
||||||
corePort ports.CorePort
|
corePort ports.CorePort
|
||||||
|
cfg config.Config
|
||||||
port int
|
port int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,11 +91,18 @@ func (g *GinAdapter) IndexHandler(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGinAdapter(corePort ports.CorePort, port int) *GinAdapter {
|
func (g *GinAdapter) ConfigHandler(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"config": g.cfg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGinAdapter(corePort ports.CorePort, cfg config.Config) *GinAdapter {
|
||||||
var adapter GinAdapter
|
var adapter GinAdapter
|
||||||
|
|
||||||
adapter.corePort = corePort
|
adapter.corePort = corePort
|
||||||
adapter.port = port
|
adapter.port = cfg.Board.Port
|
||||||
|
adapter.cfg = cfg
|
||||||
|
|
||||||
//adapter.router = gin.Default()
|
//adapter.router = gin.Default()
|
||||||
adapter.router = gin.New()
|
adapter.router = gin.New()
|
||||||
@ -104,6 +113,7 @@ func NewGinAdapter(corePort ports.CorePort, port int) *GinAdapter {
|
|||||||
adapter.router.GET("/channel/:id", adapter.ChannelByIDHandler)
|
adapter.router.GET("/channel/:id", adapter.ChannelByIDHandler)
|
||||||
adapter.router.GET("/time", adapter.TimestampHandler)
|
adapter.router.GET("/time", adapter.TimestampHandler)
|
||||||
adapter.router.GET("/data", adapter.DataHandler)
|
adapter.router.GET("/data", adapter.DataHandler)
|
||||||
|
adapter.router.GET("/config", adapter.ConfigHandler)
|
||||||
|
|
||||||
adapter.router.LoadHTMLGlob("./templates/*.tmpl")
|
adapter.router.LoadHTMLGlob("./templates/*.tmpl")
|
||||||
adapter.router.Static("/assets", "./static")
|
adapter.router.Static("/assets", "./static")
|
||||||
|
Loading…
Reference in New Issue
Block a user