diff --git a/data/esbuild.mjs b/data/esbuild.mjs
index 7c51538..63d1a05 100644
--- a/data/esbuild.mjs
+++ b/data/esbuild.mjs
@@ -3,6 +3,7 @@ import { sassPlugin } from "esbuild-sass-plugin";
import htmlPlugin from '@chialab/esbuild-plugin-html';
import handlebarsPlugin from "esbuild-plugin-handlebars";
import { clean } from 'esbuild-plugin-clean';
+import { copy } from 'esbuild-plugin-copy';
import postcss from "postcss";
import autoprefixer from "autoprefixer";
@@ -11,7 +12,7 @@ const hbsOptions = {
additionalHelpers: { splitText: "helpers.js" },
additionalPartials: {},
precompileOptions: {}
- }
+}
esbuild
.build({
@@ -29,7 +30,7 @@ esbuild
plugins: [
clean({
patterns: ['./build/*']
- }),
+ }),
htmlPlugin(),
sassPlugin({
async transform(source) {
@@ -40,7 +41,15 @@ esbuild
},
}),
handlebarsPlugin(hbsOptions),
-
+ copy({
+ // this is equal to process.cwd(), which means we use cwd path as base path to resolve `to` path
+ // if not specified, this plugin uses ESBuild.build outdir/outfile options as base path.
+ resolveFrom: 'cwd',
+ assets: {
+ from: ['./src/api.*'],
+ to: ['./build'],
+ },
+ })
],
minify: true,
metafile: false,
diff --git a/data/package.json b/data/package.json
index 2ef41d5..0963773 100644
--- a/data/package.json
+++ b/data/package.json
@@ -14,6 +14,7 @@
"autoprefixer": "^10.4.16",
"bootstrap": "^5.3.2",
"esbuild-plugin-clean": "^1.0.1",
+ "esbuild-plugin-copy": "^2.1.1",
"esbuild-plugin-handlebars": "^1.0.2",
"esbuild-sass-plugin": "^2.16.0",
"handlebars": "^4.7.7",
diff --git a/data/src/api.html b/data/src/api.html
new file mode 100644
index 0000000..27491bb
--- /dev/null
+++ b/data/src/api.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ BTClock API
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data/src/api.json b/data/src/api.json
new file mode 100644
index 0000000..5343ed5
--- /dev/null
+++ b/data/src/api.json
@@ -0,0 +1,345 @@
+{
+ "openapi": "3.0.3",
+ "info": {
+ "title": "BTClock API",
+ "version": "3.0",
+ "description": "BTClock V3 API"
+ },
+ "servers": [
+ {
+ "url": "/api/"
+ }
+ ],
+ "paths": {
+ "/status": {
+ "get": {
+ "tags": [
+ "system"
+ ],
+ "summary": "Get current status",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/system_status": {
+ "get": {
+ "tags": [
+ "system"
+ ],
+ "summary": "Get system status",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/settings": {
+ "get": {
+ "tags": [
+ "system"
+ ],
+ "summary": "Get current settings",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "system"
+ ],
+ "summary": "Save current settings",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Settings"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/action/pause": {
+ "get": {
+ "tags": [
+ "timer"
+ ],
+ "summary": "Pause screen rotation",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/action/timer_restart": {
+ "get": {
+ "tags": [
+ "timer"
+ ],
+ "summary": "Restart screen rotation",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/show/screen/{id}": {
+ "get": {
+ "tags": [
+ "screens"
+ ],
+ "summary": "Set screen to show",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "schema": {
+ "type": "integer",
+ "default": 1
+ },
+ "required": true,
+ "description": "ID of screen to show"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/show/text/{text}": {
+ "get": {
+ "tags": [
+ "screens"
+ ],
+ "summary": "Set text to show",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "text",
+ "schema": {
+ "type": "string",
+ "default": "text"
+ },
+ "required": true,
+ "description": "Text to show"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/show/custom": {
+ "post": {
+ "tags": [
+ "screens"
+ ],
+ "summary": "Set text to show (advanced)",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomText"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/full_refresh": {
+ "get": {
+ "tags": [
+ "system"
+ ],
+ "summary": "Force full refresh of all displays",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/lights/{color}": {
+ "get": {
+ "tags": [
+ "lights"
+ ],
+ "summary": "Turn on LEDs with specific color",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "color",
+ "schema": {
+ "type": "string",
+ "default": "FFCC00"
+ },
+ "required": true,
+ "description": "Color in RGB hex"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/lights/off": {
+ "get": {
+ "tags": [
+ "lights"
+ ],
+ "summary": "Turn LEDs off",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ },
+ "/restart": {
+ "get": {
+ "tags": [
+ "system"
+ ],
+ "summary": "Restart BTClock",
+ "responses": {
+ "200": {
+ "description": "successful operation"
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Settings": {
+ "type": "object",
+ "properties": {
+ "fetchEurPrice": {
+ "type": "boolean",
+ "description": "Fetch EUR price instead of USD"
+ },
+ "fgColor": {
+ "type": "string",
+ "default": 16777215,
+ "description": "ePaper foreground (text) color"
+ },
+ "bgColor": {
+ "type": "string",
+ "default": 0,
+ "description": "ePaper background color"
+ },
+ "ledTestOnPower": {
+ "type": "boolean",
+ "default": true,
+ "description": "Do LED test on power-on"
+ },
+ "ledFlashOnUpd": {
+ "type": "boolean",
+ "default": false,
+ "description": "Flash LEDs on new block"
+ },
+ "mdnsEnabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable mDNS"
+ },
+ "otaEnabled": {
+ "type": "boolean",
+ "default": true,
+ "description": "Enable over-the-air updates"
+ },
+ "stealFocusOnBlock": {
+ "type": "boolean",
+ "default": false,
+ "description": "Steal focus on new block"
+ },
+ "mcapBigChar": {
+ "type": "boolean",
+ "default": false,
+ "description": "Use big characters for market cap screen"
+ },
+ "mempoolInstance": {
+ "type": "string",
+ "default": "mempool.space",
+ "description": "Mempool.space instance to connect to"
+ },
+ "ledBrightness": {
+ "type": "integer",
+ "default": 128,
+ "description": "Brightness of LEDs"
+ },
+ "fullRefreshMin": {
+ "type": "integer",
+ "default": 60,
+ "description": "Full refresh time of ePaper displays in minutes"
+ },
+ "screen[0]": {
+ "type": "boolean"
+ },
+ "screen[1]": {
+ "type": "boolean"
+ },
+ "screen[2]": {
+ "type": "boolean"
+ },
+ "screen[3]": {
+ "type": "boolean"
+ },
+ "screen[4]": {
+ "type": "boolean"
+ },
+ "screen[5]": {
+ "type": "boolean"
+ },
+ "tzOffset": {
+ "type": "integer",
+ "default": 60,
+ "description": "Timezone offset in minutes"
+ },
+ "minSecPriceUpd": {
+ "type": "integer",
+ "default": 30,
+ "description": "Minimum time between price updates in seconds"
+ },
+ "timePerScreen": {
+ "type": "integer",
+ "default": 30,
+ "description": "Time between screens when rotating in minutes"
+ }
+ }
+ },
+ "CustomText": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 7,
+ "maxItems": 7
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/data/src/css/style.scss b/data/src/css/style.scss
index 348d289..37abcbc 100644
--- a/data/src/css/style.scss
+++ b/data/src/css/style.scss
@@ -87,7 +87,8 @@ div#output .btclock {
margin: 0 auto;
.digit,
- .splitText {
+ .splitText,
+ .mediumText {
border: 2px solid gold;
border-radius: 8px;
diff --git a/data/src/index.html b/data/src/index.html
index 7c151e5..787cb78 100644
--- a/data/src/index.html
+++ b/data/src/index.html
@@ -13,10 +13,18 @@
-