add webserver components, some webserver fices and improvements in templating, add real time history chart

This commit is contained in:
2020-01-07 00:21:27 +01:00
parent ed53611e0f
commit ef7866a29f
50 changed files with 3594 additions and 2 deletions
+54
View File
@@ -0,0 +1,54 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 660 440">
<style>
.ticks, .frame {
stroke-width: 1px;
fill: none;
stroke: black;
}
path.major {
stroke-width: 2px;
}
.ylabels text {
font-size: 10px;
text-anchor: end;
font-family: Droid Sans, sans-serif;
vertical-align: middle;
}
.grid {
stroke-dasharray: 4;
stroke: #999;
}
.series {
stroke-width: 2px;
fill: none;
}
</style>
<g transform="translate(50,15)">
<path d="M100,0 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400"
class="grid" transform="translate(0,0)" id="grid-v" />
<path d="M0,100 h600m-600,100 h600m-600,100 h600m-600,100"
class="grid" stroke-dashoffset="0" id="grid-h" />
<path d="M-10,0 h10m-10,100 h10m-10,100 h10m-10,100 h10m-10,100 h10" class="ticks" />
<path d="M-5,10
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5" class="ticks" />
<g class="series">
<path d="M0,400L600,0" stroke="blue" id="ser-set" />
<path d="M0,0L300,100L600,400" stroke="red" id="ser-actual" />
</g>
<path d="M0,0h600v400h-600Z" class="frame" />
<g class="ylabels" transform="translate(0,3)">
<text x="-15" y="0">400 °C</text>
<text x="-15" y="100">300 °C</text>
<text x="-15" y="200">200 °C</text>
<text x="-15" y="300">100 °C</text>
<text x="-15" y="400">0 °C</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

+137
View File
@@ -0,0 +1,137 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Breadflow Web Control</title>
<style>
* {
box-sizing: content-box;
}
h1 {
text-align: center;
}
#ctab {
width: 1400px;
margin: 0 auto;
border: 1px solid #ccc;
border-collapse: collapse;
}
#td-side {
border-left: 1px solid #ccc;
width: 340px;
padding: 15px;
vertical-align: top;
padding-top: 22px;
}
#td-img {
vertical-align: top;
}
</style>
</head>
<body>
<h1>Breadflow {version}</h1>
<table id="ctab">
<tr>
<td id="td-img">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 660 430">
<style>
.ticks, .frame {
stroke-width: 1px;
fill: none;
stroke: black;
}
path.major {
stroke-width: 2px;
}
.ylabels text {
font-size: 10px;
text-anchor: end;
font-family: Droid Sans, sans-serif;
vertical-align: middle;
}
.grid {
stroke-dasharray: 2;
stroke: #dbdbdb;
}
.series {
stroke-width: 2px;
fill: none;
}
</style>
<g transform="translate(50,15)">
<path d="M100,0 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400 v400"
class="grid" transform="translate(0,0)" id="grid-v" />
<path d="M0,100 h600m-600,100 h600m-600,100 h600m-600,100"
class="grid" stroke-dashoffset="0" id="grid-h" />
<path d="M-10,0 h10m-10,100 h10m-10,100 h10m-10,100 h10m-10,100 h10" class="ticks" />
<path d="M-5,10
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5" class="ticks" />
<g class="series">
<path d="{ser-set}" stroke="blue" id="ser-set" /><!--M0,400L600,0-->
<path d="{ser-act}" stroke="red" id="ser-act" /><!--M0,0L300,100L600,400-->
</g>
<path d="M0,0h600v400h-600Z" class="frame" />
<g class="ylabels" transform="translate(0,3)">
<text x="-15" y="0">400 °C</text>
<text x="-15" y="100">300 °C</text>
<text x="-15" y="200">200 °C</text>
<text x="-15" y="300">100 °C</text>
<text x="-15" y="400">0 °C</text>
</g>
</g>
</svg>
</td>
<td id="td-side">
Sidebar
</td>
</tr>
</table>
<script>
var Qi = function (x) { return document.getElementById(x) };
function update(data) {
if (data) {
let rows = data.split('\x1e');
rows.forEach(function (v) {
let [k, va] = v.split('\x1f');
switch (k) {
case 'ser-set':
Qi('ser-set').setAttribute('d', va);
break;
case 'ser-act':
Qi('ser-act').setAttribute('d', va);
break;
case 'timeshift':
Qi('grid-v').setAttribute('transform', 'translate(-'+(va*5)+',0)');
Qi('grid-h').setAttribute('stroke-dashoffset', -va * 5);
break;
}
});
} else {
var xhr=new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState===4){
if (xhr.status===200) {
update(xhr.responseText);
}
setTimeout(update, 500);
}
};
xhr.onerror = function () {
setTimeout(update, 500);
};
xhr.open('GET', '/data');
xhr.send();
}
}
setTimeout(update, 500);
</script>
+15
View File
@@ -0,0 +1,15 @@
// Generated by 'rebuild_file_tables'
#include <stdint.h>
#include "files_enum.h"
extern const uint8_t _binary_favicon_ico_start[];
extern const uint8_t _binary_favicon_ico_end[];
extern const uint8_t _binary_index_html_start[];
extern const uint8_t _binary_index_html_end[];
const struct embedded_file_info EMBEDDED_FILE_LOOKUP[] = {
[FILE_FAVICON_ICO] = {_binary_favicon_ico_start, _binary_favicon_ico_end, "favicon.ico", "image/vnd.microsoft.icon"},
[FILE_INDEX_HTML] = {_binary_index_html_start, _binary_index_html_end, "index.html", "text/html"},
};
const size_t EMBEDDED_FILE_LOOKUP_LEN = 2;
+13
View File
@@ -0,0 +1,13 @@
// Generated by 'rebuild_file_tables'
#ifndef _EMBEDDED_FILES_ENUM_H
#define _EMBEDDED_FILES_ENUM_H
#include "fileserver/embedded_files.h"
enum embedded_file_id {
FILE_FAVICON_ICO = 0,
FILE_INDEX_HTML = 1
};
#endif // _EMBEDDED_FILES_ENUM_H
+163
View File
@@ -0,0 +1,163 @@
#!/usr/bin/env php
<?php
// This script rebuilds the static files enum, extern symbols pointing to the embedded byte buffers,
// and the look-up structs table. To add more files, simply add them in the 'files' directory.
// Note that all files will be accessible by the webserver, unless you filter them in embedded_files.c.
// List all files
$files = scandir(__DIR__.'/embed');
$files = array_filter(array_map(function ($f) {
if (!is_file(__DIR__.'/embed/'.$f)) return null;
if (preg_match('/^\.|\.kate-swp|\.bak$|~$|\.sh|\.ignore\..*$/', $f)) return null;
echo "Found: $f\n";
return $f;
}, $files));
sort($files);
$formatted = array_filter(array_map(function ($f) {
return "\"files/embed/$f\"";
}, $files));
$cmake = file_get_contents(__DIR__.'/../CMakeLists.txt');
$cmake = preg_replace('/#begin staticfiles\n.*#end staticfiles/s',
"#begin staticfiles\n".
"# generated by rebuild_file_tables\n".
"set(COMPONENT_EMBED_FILES\n ".
implode("\n ", $formatted) . ")\n".
"#end staticfiles",
$cmake);
file_put_contents(__DIR__.'/../CMakeLists.txt', $cmake);
// Generate a list of files
$num = 0;
$enum_keys = array_map(function ($f) use(&$num) {
$a = preg_replace("/[^A-Z0-9_]+/", "_", strtoupper($f));
return 'FILE_'. $a.' = '.($num++);
}, $files);
$keylist = implode(",\n ", $enum_keys);
$struct_array = [];
$externs = array_map(function ($f) use (&$struct_array) {
$a = preg_replace("/[^A-Z0-9_]+/", "_", strtoupper($f));
$start = '_binary_'. strtolower($a).'_start';
$end = '_binary_'. strtolower($a).'_end';
static $mimes = array(
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'php' => 'text/html',
'css' => 'text/css',
'js' => 'application/javascript',
'json' => 'application/json',
'xml' => 'application/xml',
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
'pem' => 'application/x-pem-file',
// images
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
// archives
'zip' => 'application/zip',
'rar' => 'application/x-rar-compressed',
'exe' => 'application/x-msdownload',
'msi' => 'application/x-msdownload',
'cab' => 'application/vnd.ms-cab-compressed',
// audio/video
'mp3' => 'audio/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
// adobe
'pdf' => 'application/pdf',
'psd' => 'image/vnd.adobe.photoshop',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
// ms office
'doc' => 'application/msword',
'rtf' => 'application/rtf',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
// open office
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
);
$parts = explode('.', $f);
$suffix = end($parts);
$mime = $mimes[$suffix] ?? 'application/octet-stream';
$len = filesize('embed/'.$f);
$struct_array[] = "[FILE_$a] = {{$start}, {$end}, \"{$f}\", \"{$mime}\"},";
return
'extern const uint8_t '.$start.'[];'."\n".
'extern const uint8_t '.$end.'[];';
}, $files);
$externlist = implode("\n", $externs);
$structlist = implode("\n ", $struct_array);
file_put_contents('files_enum.h', <<<FILE
// Generated by 'rebuild_file_tables'
#ifndef _EMBEDDED_FILES_ENUM_H
#define _EMBEDDED_FILES_ENUM_H
#include "fileserver/embedded_files.h"
enum embedded_file_id {
$keylist
};
#endif // _EMBEDDED_FILES_ENUM_H
FILE
);
$files_count = count($struct_array);
file_put_contents("files_enum.c", <<<FILE
// Generated by 'rebuild_file_tables'
#include <stdint.h>
#include "files_enum.h"
$externlist
const struct embedded_file_info EMBEDDED_FILE_LOOKUP[] = {
$structlist
};
const size_t EMBEDDED_FILE_LOOKUP_LEN = $files_count;
FILE
);