1
0
mirror of https://github.com/s00500/ESPUI.git synced 2025-07-02 23:30:17 +00:00

87 Commits
1.6.3 ... 2.0.2

Author SHA1 Message Date
4827688635 Version 2.0.2
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-10-19 08:57:59 +02:00
b71bc81c0d Fixing rebase errors with littlefs/debug refactor
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-10-18 11:06:38 +02:00
a6ddd48abb Fix all other occurences
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-10-17 22:46:22 +02:00
8c0161b181 Fix prepare fs example
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-10-16 14:47:32 +02:00
3cf1aa7f49 Fix littleFS does not exist on esp32
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-10-16 14:47:29 +02:00
313a069d4c Change idcounter to start at 1, closes #95 2020-10-02 19:08:45 +02:00
34d974b03b Merge pull request #97 from ericBcreator/add_tab_callback_function
Add tab callback function
2020-10-02 19:04:26 +02:00
1de52c939f Add files via upload 2020-10-01 20:28:22 +02:00
950a1fb029 Add files via upload 2020-10-01 20:27:01 +02:00
5a167091cc Update controls.js 2020-10-01 18:57:24 +02:00
57a81dbee3 Update ESPUI.cpp 2020-10-01 18:51:54 +02:00
acaf6898fd Update controls.js 2020-10-01 18:49:18 +02:00
37bbb9208d Merge pull request #91 from enwi/master
Reduce HEAP usage
2020-10-01 18:37:45 +02:00
6b2ef81b12 Fix include of ESPUI header 2020-10-01 18:04:28 +02:00
1e5ee117c5 Use DEBUG_ESPUI to en/disable debug code from being compiled
Include clang-format file for formatting code and format code
2020-10-01 18:04:28 +02:00
db4164f621 Reduce heap usage by using F and PSTR 2020-10-01 18:04:28 +02:00
bfd645d7a1 Use const String& to reduce IROM usage 2020-10-01 18:04:28 +02:00
99cf344d93 Changes suggested in #93
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-09-24 21:50:28 +02:00
291ff8ed80 Bump verison
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-08-26 22:17:18 +02:00
cda1a573d6 cleanup
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-08-26 22:16:02 +02:00
6506f6fe1c Fixing sliders not updating properly
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-08-26 22:16:02 +02:00
eec13e4934 No reload per default, just send JsonDom 2020-08-26 22:15:56 +02:00
81366af7f1 Add remControl() method for remove contols 2020-08-26 22:13:38 +02:00
1b7af71d29 Fix littlefs include
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-08-26 22:13:21 +02:00
c02f357d84 Merge pull request #89 from bastiengrignon/feature/spiffs-update
Update filesystem
2020-06-30 19:30:59 +02:00
fffe4a8641 Update filesystem from deprecated SPIFFS to LittleFS 2020-06-30 12:39:51 +02:00
585c1608b8 Fix update_gauge typo, Close #69 2020-06-01 18:09:15 +02:00
5a6b92bb5f Closes #74 Adds chinese facilino translation 2020-06-01 18:09:15 +02:00
54aeaacf86 Merge pull request #64 from per1234/depends
Specify library dependencies in library.properties
2020-04-03 10:14:39 +02:00
3afd518399 Connect to correct websocket on different port 2020-01-27 13:13:47 +01:00
65dc2d81a3 Specify library dependencies in library.properties
Specifying the library dependencies in the depends field of library.properties causes the Arduino Library Manager (Arduino IDE 1.8.10 and newer) to offer to install any missing dependencies during installation of this library. "arduino-cli lib install" will automatically install the dependencies (arduino-cli 0.7.0 and newer).
2020-01-06 00:09:22 -08:00
22f6b3922e Update library.json
Remove ArduinoJSON version constraint
2019-12-30 20:02:12 +01:00
e5475bc099 Merge pull request #51 from s00500/2.0.0
WIP: 2.0.0
2019-12-29 15:05:19 +01:00
301fe0e906 Merge branch 'master' into 2.0.0 2019-12-29 15:05:00 +01:00
36fce6bf25 Final Updates for 2.0 Readme 2019-12-29 15:03:52 +01:00
e0ee932fff new tab image 2019-12-29 14:50:09 +01:00
71576d7686 More ducumentation 2019-12-29 14:35:54 +01:00
2b4141fed3 Readme getting ready for 2.0 2019-12-28 23:32:45 +01:00
c5dd493cb0 fixing compile issues 2019-12-28 22:28:55 +01:00
daede8799a sync up examples 2019-12-28 21:30:57 +01:00
f00f7601f4 Some updates to gui example 2019-12-28 15:08:23 +01:00
bd7e324a31 fix sliderupdate 2019-12-28 15:05:27 +01:00
9764db9789 Increase timeout for connecting existing network and add continuous slider mode #60 2019-12-28 14:54:41 +01:00
681a00b3ed reformate slider 2019-12-28 14:17:29 +01:00
79046d7bd0 remove graph logging 2019-12-27 20:27:10 +01:00
4b0f8e86b4 #10 Enable storing to localstorage 2019-12-27 16:57:11 +01:00
bcddcfc311 #63 add variabbles to public scope of espui 2019-12-27 16:30:15 +01:00
fe45ed8010 #63 Add variables for jsonDynamicDocument Sizes 2019-12-27 16:27:42 +01:00
0323920a0d Rename new api and some readme cleaning 2019-12-27 15:43:36 +01:00
fcc80b5843 Remove accel from example 2019-12-27 15:37:08 +01:00
9e5756ceef Update Roadmap 2019-12-27 15:36:54 +01:00
e317d25977 Make AsyncServer instance Pubblic 2019-12-27 15:36:24 +01:00
75ec2590f6 Update js stuff 2019-12-27 15:36:12 +01:00
80621bda22 update version in properties file 2019-12-27 15:33:55 +01:00
79f509da74 #10 Graph points working
- timestap still not great
2019-04-15 15:32:14 +02:00
bff259008f Graph Frontend work
- Adds graph js file
- Adds graph styles
2019-04-15 13:49:15 +02:00
36cfe78205 Knowing websocket msg string length 2019-04-15 12:41:22 +02:00
2c6aaf82f4 two strings less 2019-04-15 12:38:09 +02:00
043ba99ea9 Adding basic structure for new widgets 2019-03-26 16:22:21 +01:00
3c69f013fc Proper wrappers
- update order of params of create functions to be simillar
- changed all numbers to be numbers
- split pad creation function
- updated examples
2019-03-24 19:18:53 +01:00
650411bac4 Consistent use of updateControl on websocket event
- rename updateControl to updateControlValue
- some earlie returns
2019-03-24 18:46:34 +01:00
b66d41a98b more reformating 2019-03-24 18:18:08 +01:00
218ebc67d9 Style change again 2019-03-24 18:10:21 +01:00
70288fc69f Hide tabsnav on :empty 2019-03-24 16:15:30 +01:00
1bb5d16082 Update name 2019-03-24 16:08:05 +01:00
a37ae5eb70 readme update 2019-03-24 16:06:42 +01:00
63b6761044 Cleanup and reformat header
- Construct inside library
- Adds setVerbosity
2019-03-24 16:06:35 +01:00
b9a087c169 Use ArduinoJson 6.10.0 2019-03-24 15:44:27 +01:00
fd12f7ad2a Version Bump 2019-03-24 15:37:47 +01:00
41563454af Update readme with roadmap for 2.0.0 2019-03-24 15:37:37 +01:00
6873052b6e Added new features, removed dependency on unique labels
- added Min/Max/Step for numbers and sliders
- labels don't have to be unique anymore; controls can't be updated by labels
- new Slider: JS + CSS
2019-03-19 09:34:16 +01:00
7125374fa3 Color of elementes are now updateable, reformatted control.js 2019-03-08 22:24:20 +01:00
00d996d8dd The Pad works again
Don't set the style of all the <ul> and <li> in the css, use the class
2019-03-08 21:17:28 +01:00
b987828a25 Preselect the right option in the select-input 2019-03-06 00:18:19 +01:00
d0c59ac659 Small bug: don't set the type to Button in ESPUIClass::slider() 2019-03-04 21:08:52 +01:00
6178e4fc22 Added the dropdown-Control
* added the Control
* added the frontend-code
* added the control to the examples "gui-newAPI.ino" and "tabbedGui.ino"
2019-03-04 21:07:39 +01:00
3c42b43fe6 Changed signature of the callback
Call the callback with a pointer instead of a copy of the Control.
Changed all the examples
2019-03-04 21:05:13 +01:00
2b31e81f50 instantiate ESPUI in prepareFileSystem.ino too 2019-03-03 23:38:29 +01:00
4ea7928fd5 Added Tabbed View
* new member of Control: parentControl
* changed addControl() to add children of elements
* added some styles in the css
* two new divs in index.html
* added frontend code to controls.js
* added new demo to demonstrate the tabbed view
2019-03-03 23:33:15 +01:00
50de3dad87 Added tabbedcontent.js (from https://github.com/elboletaire/tabbedcontent) 2019-03-03 23:27:11 +01:00
acce17b82c IDs are uint16_t, removed not used member ESPUIClass::cIndex 2019-03-03 23:27:11 +01:00
6c8f113861 Added a Demo with the new API 2019-03-03 23:27:04 +01:00
a4989b4eb0 Reordered arguments of ESPUIClass::addControl
The arguments value, color and callback have defaults
2019-03-03 21:50:06 +01:00
37ce571b9c added ESPUI::updateLabel (works like ESPUI::print) 2019-03-03 21:46:38 +01:00
6810f7432f Moved examples/gui/data to data/ and adjusted tools/*.py 2019-03-03 21:23:39 +01:00
e542ce0178 Updated Demo for changes in the API
updated the gui.ino to reflect the changes in the API:
* reformated/reindented, minor cleanups
* instantation of ESPUI in the users application
* automatic swichtover to station mode if given network is not found
2019-03-03 21:17:49 +01:00
8865416331 Updated API
* Sourcecode reindented/reformated, added scopes to all the ifs
* Linked list for holding all the controls
* IDs are autogenerated, Control is now a class
* generalised API for creating controls, removed a lot of redundant code
* a lot of glue for the old API
* check if callback exists before calling it
* Instantation moved out of ESPUI.cpp, must be in the users application
* verbose printing on the serial line dependent of instantation ESPUI(...)
* streamlined begin(...), make authentification optional
2019-03-03 21:13:45 +01:00
47 changed files with 4556 additions and 2074 deletions

58
.clang-format Executable file
View File

@ -0,0 +1,58 @@
---
# Based on Webkit style
BasedOnStyle: Webkit
IndentWidth: 4
ColumnLimit: 120
---
Language: Cpp
Standard: Cpp11
# Pointers aligned to the left
DerivePointerAlignment: false
PointerAlignment: Left
AccessModifierOffset: -4
AllowShortFunctionsOnASingleLine: Inline
AlwaysBreakTemplateDeclarations: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakConstructorInitializers: BeforeColon
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
Cpp11BracedListStyle: true
FixNamespaceComments: true
IncludeBlocks: Regroup
IncludeCategories:
# C++ standard headers (no .h)
- Regex: '<[[:alnum:]_-]+>'
Priority: 1
# Extenal libraries (with .h)
- Regex: '<[[:alnum:]_./-]+>'
Priority: 2
# Headers from same folder
- Regex: '"[[:alnum:]_.-]+"'
Priority: 3
# Headers from other folders
- Regex: '"[[:alnum:]_/.-]+"'
Priority: 4
IndentCaseLabels: false
NamespaceIndentation: All
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterTemplateKeyword: true
SpacesInAngles: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
UseTab: Never

321
README.md
View File

@ -14,71 +14,90 @@ So if you either don't know how or just don't want to waste time: this is your
simple solution user interface without the need of internet connectivity or any
additional servers.
I completely rewrote the EasyUI Library created by ayushsharma82
[Here](https://github.com/ayushsharma82/) Now it uses ESPAsyncWebserver and is
mainly to be used with the ESP32 Processor.
The Library runs fine on any kind of **ESP8266** and **ESP32** (NodeMCU Boards, usw)
# Important notes
## Changelog for 2.0:
Currently ESPUI only supports ArduinoJSON 5.x, please keep that in mind! Version
6 support is work in progress
- ArduinoJSON 6.10.0 Support
- split pad into pad and padWithCenter
- Cleaned Order or parameters on switch
- cleaned Order of parameters on pad
- Changes all numbers to actually be numbers (slider value, number value, min and max)
### Added features
- Tabs by @eringerli #45
- Generic API by @eringerli
- Min Max on slider by @eringerli
- OptionList by @eringerli
- Public Access to ESPAsyncServer
- Graph Widget (Persist save graph in local storage #10)
## Further Roadmap
- Slider css issues
- implement Gauge
- File upload ?
## Dependencies
This library is dependent on the following libraries to function properly.
- [ESPAsyncWebserver](https://github.com/me-no-dev/ESPAsyncWebServer)
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson) **(VERSIONS 5.x only
currently)**
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson) (Last tested with
version 6.10.0)
**Plus for ESP8266**
- [ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP)
**Additionally necessary for ESP32**
- [AsyncTCP](https://github.com/me-no-dev/AsyncTCP)
- (_For ESP8266_) [ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP)
- (_For ESP32_) [AsyncTCP](https://github.com/me-no-dev/AsyncTCP)
## How to Install
Make sure all the dependencies are installed, then install like so:
#### Using PlattformIO (_recommended_)
Just include this library as a dependency on lib_deps like so:
```
lib_deps =
ESPUI
ESPAsyncWebserver
ESPAsyncTCP # or AsyncTCP on ESP32
```
#### Directly Through Arduino IDE (_recommended_)
You can find this Library in the Arduino IDE library manager Go to Sketch >
Include Library > Library Manager > Search for "ESPUI" > Install
#### Manual Install
#### Manual Install Arduino IDE
For Windows: Download the
_For Windows:_ Download the
[Repository](https://github.com/s00500/ESPUI/archive/master.zip) and extract the
.zip in Documents>Arduino>Libraries>{Place "ESPUI" folder Here}
For Linux: Download the
_For Linux:_ Download the
[Repository](https://github.com/s00500/ESPUI/archive/master.zip) and extract the
.zip in Sketchbook/Libraries/{Place "ESPUI" folder Here}
For macOs: Download the
_For macOs:_ Download the
[Repository](https://github.com/s00500/ESPUI/archive/master.zip) and extract the
.zip in ~/Documents/Arduino/libraries/{Place "ESPUI" folder Here}
#### Manually through IDE
Download the [Repository](https://github.com/s00500/ESPUI/archive/master.zip),
Go to Sketch>Include Library>Add .zip Library> Select the Downloaded .zip File.
## Getting started
ESPUI serves several files to the browser to build up its webinterface. This can
be achieved in 2 ways: _PROGMEM_ or _SPIFFS_
ESPUI serves several files to the browser to build up its web interface. This
can be achieved in 2 ways: _PROGMEM_ or _SPIFFS_
_When `ESPUI.begin()` is called the default is serving files from Memory and
ESPUI should work out of the box!_
But if this causes your program to _use too much memory_ you can burn the files
into the SPIFFS filesystem on the ESP. There are now two ways to do this: you
can either use the ESP file upload tool or you use the library function
`ESPUI.prepareFileSystem()`
**OPTIONAL:** But if this causes your program to _use too much memory_ you can
burn the files into the SPIFFS filesystem on the ESP. There are now two ways to
do this: you can either use the ESP file upload tool or you use the library
function `ESPUI.prepareFileSystem()`
#### Simple filesystem preparation (_recommended_)
@ -88,58 +107,37 @@ will create all needed files. Congratulations, you are done, from now on you
just need to to this again when there is a library update, or when you want to
use another chip :-) Now you can upload your normal sketch, when you do not call
the `ESPUI.prepareFileSystem()` function the compiler will strip out all the
unnecessary that is already saved in the chip's filesystem and you have more
programm memory to work with.
#### Manual way (mainly for development)
To do this download and install me-no-devs wonderful
[ESP32 sketch data uploader](https://github.com/me-no-dev/arduino-esp32fs-plugin)
or for ESP8266
[ESP8266 sketch data uploader](https://github.com/esp8266/arduino-esp8266fs-plugin)
Then open the **gui** example sketch and select "Upload Sketch Data" from the
Tools menu for your processor. Now you are set to go and use any code you want
to with this library
unnecessary strings that are already saved in the chip's filesystem and you have
more program memory to work with.
## User interface Elements
- Label (updateable)
- Label
- Button
- Switch (updateable)
- Switch
- Control pad
- Control pad with center button
- Slider
- Text Input (updateable)
- Numberinput (updateable)
- Text Input
- Numberinput
- Graph
- Option select
Checkout the example for the usage
Checkout the example for the usage or see the detailed info below
## Available colors:
- COLOR_TURQUOISE
- COLOR_EMERALD
- COLOR_PETERRIVER
- COLOR_WETASPHALT
- COLOR_SUNFLOWER
- COLOR_CARROT
- COLOR_ALIZARIN
- COLOR_NONE
- Turquoise
- Emerald
- Peterriver
- Wetasphalt
- Sunflower
- Carrot
- Alizarin
- Dark
- None
## Roadmap :
- ~~Setup SPIFFS using values in program memory~~
- ~~ESP8266 support~~
- ~~PlattformIO Integration~~
- ~~Multiline Labels~~
- ~~GZip Files and serve from memory~~
- Datagraph output -> _WIP_
- ~~Number input ~~
- ~~Text input ~~
- Dokumentation for Text and number widget
- Number min and max value
- proper return value (as int and not as string) for slider
- Maybe a slider range setting, meanwhile please use _map()_
(Use like `ControlColor::Sunflower`)
## Documentation
@ -147,17 +145,15 @@ The heart of ESPUI is
[ESPAsyncWebserver](https://github.com/me-no-dev/ESPAsyncWebServer). ESPUI's
frontend is based on [Skeleton CSS](http://getskeleton.com/) and jQuery-like
lightweight [zepto.js](https://zeptojs.com/) for Handling Click Events Etc. The
communication between the _ESP32_ and the client browser works using web
communication between the _ESP_ and the client browser works using web
sockets. ESPUI does not need network access and can be used in standalone access
point mode. All assets are loaded from the internal SPIFFS filesystem of the
ESP32.
point mode, all resources are loaded directly from the ESPs memory.
This section will explain in detail how the Library is to be used from the
Arduino code side. As of now the Facilino blocks are not implemented. In the
arduino setup() routine the interface can be customised by adding UI Elements.
Arduino code side. In the arduino `setup()` routine the interface can be customised by adding UI Elements.
This is done by calling the corresponding library methods on the Library object
ESPUI. Eg: `ESPUI.button(button, &myCallback);` creates a button in the
interface that calls the myCallback function when changed. All buttons and
`ESPUI`. Eg: `ESPUI.button("button", &myCallback);` creates a button in the
interface that calls the `myCallback(Control *sender, int value)` function when changed. All buttons and
items call their callback whenever there is a state change from them. This means
the button will call the callback when it is pressed and also again when it is
released. To separate different events an integer number with the event name is
@ -169,8 +165,11 @@ of the UI library:
![Buttons](https://github.com/s00500/ESPUI/blob/master/docs/ui_button.png)
Buttons have a name and a callback value. They have one event for press and one
for release.
Buttons have a name and a callback value. They have one event for press (`B_DOWN`) and one
for release (`B_UP`).
- B_DOWN
- B_UP
#### Switch
@ -178,8 +177,11 @@ for release.
Switches sync their state on all connected devices. This means when you change
their value they change visibly on all tablets or computers that currently
display the interface. They also have two types of events: one for turning on
and one for turning off.
display the interface. They also have two types of events: one when turning on (`S_ACTIVE`)
and one when turning off (`S_INACTIVE`).
- S_ACTIVE
- S_INACTIVE
#### Buttonpad
@ -190,13 +192,24 @@ useful for con-trolling all kinds of movements of vehicles or also of course our
walking robots. They use a single callback per pad and have 8 or 10 different
event types to differentiate the button actions.
- P_LEFT_DOWN
- P_LEFT_UP
- P_RIGHT_DOWN
- P_RIGHT_UP
- P_FOR_DOWN
- P_FOR_UP
- P_BACK_DOWN
- P_BACK_UP
- P_CENTER_DOWN
- P_CENTER_UP
#### Labels
![labels](https://github.com/s00500/ESPUI/blob/master/docs/ui_labels.png)
Labels are a nice tool to get information from the robot to the user interface.
This can be done to show states, values of sensors and configuration parameters.
To send data from the code use `ESP.print(labelId, Text);` . Labels get a name
To send data from the code use `ESP.print(labelId, "Text");` . Labels get a name
on creation and a initial value. The name is not changeable once the UI
initialised.
@ -205,36 +218,140 @@ the normal `<br>` tag in the string you print to the label
#### Slider
![labels](https://github.com/s00500/ESPUI/blob/master/docs/ui_slider.png)
![slider](https://github.com/s00500/ESPUI/blob/master/docs/ui_slider.png)
The Slider can be used to slide through a value from 1 to 100. Slides provide
realtime data, are touch compatible and can be used to for example control a
Servo. The current value is shown while the slider is dragged in a little bubble
over the handle.
over the handle. In the Callback the slider does not return an int but a String.
Use the .toInt function to convert the value, see the **gui** example to check how it works.
#### Initialisation of the UI
A slider usually only sends a new value when it is released to save the esps from being spammed with values. This behaviour can be cahnged globally using a property of the ESPUI object before `begin()`:
After all the elements are configured you can use `ESPUI.begin(“Some Title”);`
to start the UI interface. (Or `ESPUI.beginSPIFFS(“Some Title”);` respectively)
```
ESPUI.sliderContinuous = true;
ESPUI.begin("ESPUI Control");
```
#### Number Input
![number](https://github.com/s00500/ESPUI/blob/master/docs/ui_number.png)
The numberinput can be used to directly input numbers to your program. You can
enter a Value into it and when you are done with your change it is sent to the
ESP.
A number box needs to have a min and a max value. To set it up just use:
`ESPUI.number("Numbertest", &numberCall, ControlColor::Alizarin, 5, 0, 10);`
#### Text Input
![text](https://github.com/s00500/ESPUI/blob/master/docs/ui_text.png)
The textinput works very similar like the number input but with a string. You
can enter a String into it and when you are done with your change it is sent to
the ESP.
#### Graph
![graph](https://github.com/s00500/ESPUI/blob/master/docs/ui_graph.png)
The graph widget can display graph points with timestamp at wich they arrive
Use `ESPUI.addGraphPoint(graphId, random(1, 50));` to add a new value at the current time, use `ESPUI.clearGraph(graphId)` to clear the entire graph.
Graph points are saved in the browser in **localstorage** to be persistant, clear local storageto remove the points or use clearGraph() from a bbutton callback to provide a clear button.
#### Option select
![option1](https://github.com/s00500/ESPUI/blob/master/docs/ui_select1.png)
![option2](https://github.com/s00500/ESPUI/blob/master/docs/ui_select2.png)
The option select works by first creating a select widget like so
`uint16_t select1 = ESPUI.addControl( ControlType::Select, "Select:", "", ControlColor::Alizarin, tab1, &selectExample );`
And then adding Options to it like seperate widgets, specifying the select as the parent:
```
ESPUI.addControl( ControlType::Option, "Option1", "Opt1", ControlColor::Alizarin, select1 );
ESPUI.addControl( ControlType::Option, "Option2", "Opt2", ControlColor::Alizarin, select1 );
ESPUI.addControl( ControlType::Option, "Option3", "Opt3", ControlColor::Alizarin, select1 );
```
Check the **tabbedGui** example for a working demo
### Using Tabs
![tabs](https://github.com/s00500/ESPUI/blob/master/docs/ui_tabs.png)
Tabs can be used to organize your widgets in pages. Check the tabbedGui example.
Tabs can be created using the generic functions like so:
`ESPUI.addControl( ControlType::Tab, "Settings 1", "Settings 1" );`
Then all widgets for the tab need to be added to it by specifying the tab as the parrent (widgets not added to a tab will be shown above the tab selctor)
`ESPUI.addControl( ControlType::Text, "Text Title:", "a Text Field", ControlColor::Alizarin, tab1, &textCall );`
### Initialisation of the UI
After all the elements are configured you can use `ESPUI.begin("Some Title");`
to start the UI interface. (Or `ESPUI.beginSPIFFS("Some Title");` respectively)
Make sure you setup a working network connection or AccesPoint **before** (See
example). The web interface can then be used from multiple devices at once and
also shows an connection status in the top bar. The library is designed to be
easy to use and can still be extended with a lot of more functionality.
gui.ino example). The web interface can then be used from multiple devices at once and
also shows an connection status in the top bar.
### Advanced: Generic creation and updates of control widgets
There are 2 generic functions to create and update controls, to see them in action check the **gui-generic-api** example.
To create a generic control use:
`uint16_t switchOne = ESPUI.addControl(ControlType::Switcher, "Switch one", "", ControlColor::Alizarin, Control::noParent, &switchExample);`
Then its value can be updated by doing:
`ESPUI.updateControlValue(status, "Start");`
You can also update other parameters of the control like its color using:
```
ESPUI.getControl(switchOne)->color = ControlColor::Carrot;
ESPUI.updateControl(switchOne);
```
### Log output
ESPUI has several different log levels. You can set them using the
`ESPUI.setVerbosity(Verbosity::VerboseJSON)` function.
Loglevels are:
- `Verbosity::Quiet` (default)
- `Verbosity::Verbose`
- `Verbosity::VerboseJSON`
VerboseJSON outputs the most debug information.
### Advanced properties
If you have many different widgets it might be necessary to adjust the JSON Buffers used internally in ESPUI before .begin() :
```
ESPUI.jsonUpdateDocumentSize = 2000; // This is the default, and this value is not affected by the amount of widgets
ESPUI.jsonInitialDocumentSize = 8000; // This is the default, adjust when you have too many widgets or options
ESPUI.begin("ESPUI Control");
```
# Notes for Development
If you want to work on the HTML/CSS/JS files, do make changes in the
`examples/gui/data` directory. When you need to transfer that code to the ESP,
run `tools/prepare_static_ui_sources.py -a` (this script needs python3 with the
modules htmlmin, jsmin and csscompressor). This will generate a) minified files
next to the original files to be uploaded with the ESP32 sketch data uploader
mentioned above and b) the C header files in `src` that contain the minified and
gzipped HTML/CSS/JS data (which are used by the **prepareFileSystem** example
sketch or when they are served from PROGMEM; see above in the section "Getting
started"). Alternatively, you can duplicate the `examples/gui` directory and
work on the copy. Then specify the `--source` and `--target` arguments to the
If you want to work on the HTML/CSS/JS files, do make changes in the _data_
directory. When you need to transfer that code to the ESP, run
`tools/prepare_static_ui_sources.py -a` (this script needs **python3** with the
modules **htmlmin**, **jsmin** and **csscompressor**). This will generate a) minified files
next to the original files and b) the C header files in `src` that contain the minified and
gzipped HTML/CSS/JS data. Alternatively, you can specify the `--source` and `--target` arguments to the
`prepare_static_ui_sources.py` script (run the script without arguments for
help).
help) if you want to use different locations.
If you don't have a python environment, you need to minify and gzip the
HTML/CSS/JS files manually. I wrote a little useful jsfiddle for this,
@ -242,9 +359,11 @@ HTML/CSS/JS files manually. I wrote a little useful jsfiddle for this,
If you change something in HTML/CSS/JS and want to create a pull request, please
do include the minified versions and corresponding C header files in your
commits.
commits. (Do **NOT** commit all the minified versions for the non changed files)
# Contribute
Liked this Library? You can **support** me by sending me a :coffee:
[Coffee](https://paypal.me/lukasbachschwell/3).
[Coffee](https://paypal.me/lukasbachschwell/5).
Otherwise I really welcome **Pull Requests**.

View File

@ -12,20 +12,25 @@
}
.card {
min-height: 100px;
margin-top: 2%;
border-radius: 6px;
box-shadow: 0 4px 4px rgba(204, 197, 185, 0.5);
padding-left: 20px;
padding-right: 20px;
margin-bottom: 10px;
min-width: 150px;
min-width: 500px;
color: #fff;
}
.card-slider {
padding-bottom: 10px;
@media (max-width: 630px) {
.card {
min-width: 98%;
}
}
.card-slider {}
.turquoise {
background: #1abc9c;
border-bottom: #16a085 3px solid;
@ -74,7 +79,7 @@
text-align: center;
color: #ffffff;
font-weight: 700;
line-height: 1;
line-height: 1.3;
margin-bottom: 5px;
display: inline-block;
white-space: nowrap;
@ -129,114 +134,145 @@
.container {
width: 98%;
}
.column,
.columns {
margin-right: 2%;
}
.column:first-child,
.columns:first-child {
margin-left: 0;
}
.one.column,
.one.columns {
width: 4.66666666667%;
}
.two.columns {
width: 13.3333333333%;
}
.three.columns {
width: 22%;
}
.four.columns {
width: 30.6666666667%;
}
.five.columns {
width: 39.3333333333%;
}
.six.columns {
width: 48%;
}
.seven.columns {
width: 56.6666666667%;
}
.eight.columns {
width: 65.3333333333%;
}
.nine.columns {
width: 74%;
}
.ten.columns {
width: 82.6666666667%;
}
.eleven.columns {
width: 91.3333333333%;
}
.twelve.columns {
width: 100%;
margin-left: 0;
}
.one-third.column {
width: 30.6666666667%;
}
.two-thirds.column {
width: 65.3333333333%;
}
.one-half.column {
width: 48%;
}
/* Offsets */
.offset-by-one.column,
.offset-by-one.columns {
margin-left: 8.66666666667%;
}
.offset-by-two.column,
.offset-by-two.columns {
margin-left: 17.3333333333%;
}
.offset-by-three.column,
.offset-by-three.columns {
margin-left: 26%;
}
.offset-by-four.column,
.offset-by-four.columns {
margin-left: 34.6666666667%;
}
.offset-by-five.column,
.offset-by-five.columns {
margin-left: 43.3333333333%;
}
.offset-by-six.column,
.offset-by-six.columns {
margin-left: 52%;
}
.offset-by-seven.column,
.offset-by-seven.columns {
margin-left: 60.6666666667%;
}
.offset-by-eight.column,
.offset-by-eight.columns {
margin-left: 69.3333333333%;
}
.offset-by-nine.column,
.offset-by-nine.columns {
margin-left: 78%;
}
.offset-by-ten.column,
.offset-by-ten.columns {
margin-left: 86.6666666667%;
}
.offset-by-eleven.column,
.offset-by-eleven.columns {
margin-left: 95.3333333333%;
}
.offset-by-one-third.column,
.offset-by-one-third.columns {
margin-left: 34.6666666667%;
}
.offset-by-two-thirds.column,
.offset-by-two-thirds.columns {
margin-left: 69.3333333333%;
}
.offset-by-one-half.column,
.offset-by-one-half.columns {
margin-left: 52%;
@ -316,18 +352,23 @@ h6 {
h1 {
font-size: 5rem;
}
h2 {
font-size: 4.2rem;
}
h3 {
font-size: 3.6rem;
}
h4 {
font-size: 3rem;
}
h5 {
font-size: 2rem;
}
h6 {
font-size: 1.5rem;
}
@ -432,10 +473,8 @@ hr {
.control {
background-color: #ddd;
background-image: linear-gradient(
hsla(0, 0%, 0%, 0.1),
hsla(0, 0%, 100%, 0.1)
);
background-image: linear-gradient(hsla(0, 0%, 0%, 0.1),
hsla(0, 0%, 100%, 0.1));
border-radius: 50%;
box-shadow: inset 0 1px 1px 1px hsla(0, 0%, 100%, 0.5),
0 0 1px 1px hsla(0, 0%, 100%, 0.75), 0 0 1px 2px hsla(0, 0%, 100%, 0.25),
@ -500,10 +539,8 @@ hr {
.control .confirm {
background-color: #ddd;
background-image: linear-gradient(
hsla(0, 0%, 0%, 0.15),
hsla(0, 0%, 100%, 0.25)
);
background-image: linear-gradient(hsla(0, 0%, 0%, 0.15),
hsla(0, 0%, 100%, 0.25));
box-shadow: inset 0 1px 1px 1px hsla(0, 0%, 100%, 0.5),
0 0 1px 1px hsla(0, 0%, 100%, 0.25), 0 0 1px 2px hsla(0, 0%, 100%, 0.25),
0 0 1px 3px hsla(0, 0%, 100%, 0.25), 0 0 1px 4px hsla(0, 0%, 100%, 0.25),
@ -576,13 +613,11 @@ hr {
.switch .in:before {
background: #fff;
background: -moz-linear-gradient(top, #fff 0%, #f0f0f0 100%);
background: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0%, #fff),
color-stop(100%, #f0f0f0)
);
background: -webkit-gradient(linear,
left top,
left bottom,
color-stop(0%, #fff),
color-stop(100%, #f0f0f0));
background: -webkit-linear-gradient(top, #fff 0%, #f0f0f0 100%);
background: -o-linear-gradient(top, #fff 0%, #f0f0f0 100%);
background: -ms-linear-gradient(top, #fff 0%, #f0f0f0 100%);
@ -601,13 +636,11 @@ hr {
.switch .in:after {
background: #f0f0f0;
background: -moz-linear-gradient(top, #f0f0f0 0%, #fff 100%);
background: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0%, #f0f0f0),
color-stop(100%, #fff)
);
background: -webkit-gradient(linear,
left top,
left bottom,
color-stop(0%, #f0f0f0),
color-stop(100%, #fff));
background: -webkit-linear-gradient(top, #f0f0f0 0%, #fff 100%);
background: -o-linear-gradient(top, #f0f0f0 0%, #fff 100%);
background: -ms-linear-gradient(top, #f0f0f0 0%, #fff 100%);
@ -629,6 +662,7 @@ hr {
font-size: 16px;
font-family: "Roboto", sans-serif;
}
.rkmd-slider input[type="range"] {
overflow: hidden;
position: absolute;
@ -636,7 +670,8 @@ hr {
height: 1px;
opacity: 0;
}
.rkmd-slider input[type="range"] + .slider {
.rkmd-slider input[type="range"]+.slider {
display: block;
position: relative;
width: 100%;
@ -644,13 +679,15 @@ hr {
border-radius: 13px;
background-color: #bebebe;
}
@media (pointer: fine) {
.rkmd-slider input[type="range"] + .slider {
.rkmd-slider input[type="range"]+.slider {
height: 4px;
border-radius: 0px;
}
}
.rkmd-slider input[type="range"] + .slider .slider-fill {
.rkmd-slider input[type="range"]+.slider .slider-fill {
display: block;
position: absolute;
width: 0%;
@ -658,7 +695,8 @@ hr {
user-select: none;
z-index: 1;
}
.rkmd-slider input[type="range"] + .slider .slider-handle {
.rkmd-slider input[type="range"]+.slider .slider-handle {
cursor: pointer;
position: absolute;
top: 12px;
@ -671,50 +709,45 @@ hr {
user-select: none;
z-index: 2;
}
@media (pointer: fine) {
.rkmd-slider input[type="range"] + .slider .slider-handle {
.rkmd-slider input[type="range"]+.slider .slider-handle {
top: -5.5px;
}
}
.rkmd-slider input[type="range"]:disabled + .slider {
.rkmd-slider input[type="range"]:disabled+.slider {
background-color: #b0b0b0 !important;
}
.rkmd-slider input[type="range"]:disabled + .slider .slider-fill,
.rkmd-slider input[type="range"]:disabled + .slider .slider-handle {
.rkmd-slider input[type="range"]:disabled+.slider .slider-fill,
.rkmd-slider input[type="range"]:disabled+.slider .slider-handle {
cursor: default !important;
background-color: #b0b0b0 !important;
}
.rkmd-slider input[type="range"]:disabled + .slider .slider-fill .slider-label,
.rkmd-slider
input[type="range"]:disabled
+ .slider
.slider-handle
.slider-label {
.rkmd-slider input[type="range"]:disabled+.slider .slider-fill .slider-label,
.rkmd-slider input[type="range"]:disabled+.slider .slider-handle .slider-label {
display: none;
background-color: #b0b0b0 !important;
}
.rkmd-slider input[type="range"]:disabled + .slider .slider-fill.is-active,
.rkmd-slider input[type="range"]:disabled + .slider .slider-handle.is-active {
.rkmd-slider input[type="range"]:disabled+.slider .slider-fill.is-active,
.rkmd-slider input[type="range"]:disabled+.slider .slider-handle.is-active {
top: -5.5px;
width: 15px;
height: 15px;
margin-left: -8px;
}
.rkmd-slider
input[type="range"]:disabled
+ .slider
.slider-fill.is-active
.slider-label,
.rkmd-slider
input[type="range"]:disabled
+ .slider
.slider-handle.is-active
.slider-label {
.rkmd-slider input[type="range"]:disabled+.slider .slider-fill.is-active .slider-label,
.rkmd-slider input[type="range"]:disabled+.slider .slider-handle.is-active .slider-label {
display: none;
border-radius: 50%;
transform: none;
}
.rkmd-slider input[type="range"]:disabled + .slider .slider-handle:active {
.rkmd-slider input[type="range"]:disabled+.slider .slider-handle:active {
box-shadow: none !important;
transform: scale(1) !important;
}
@ -741,6 +774,7 @@ hr {
-webkit-transition: all 0.2s ease;
transition: all 0.2s ease;
}
@media (pointer: fine) {
.rkmd-slider.slider-discrete .slider .slider-handle .slider-label {
left: -2px;
@ -765,17 +799,20 @@ hr {
-ms-user-select: none;
user-select: none;
}
@media (pointer: fine) {
.rkmd-slider.slider-discrete .slider .slider-handle .slider-label span {
font-size: 12px;
}
}
.rkmd-slider.slider-discrete .slider .slider-handle.is-active {
top: 0px;
margin-left: -2px;
width: 4px;
height: 4px;
}
.rkmd-slider.slider-discrete .slider .slider-handle.is-active .slider-label {
top: -15px;
left: -2px;
@ -783,11 +820,8 @@ hr {
-webkit-transform: rotate(-45deg) translate(23px, -25px);
transform: rotate(-45deg) translate(23px, -25px);
}
.rkmd-slider.slider-discrete
.slider
.slider-handle.is-active
.slider-label
span {
.rkmd-slider.slider-discrete .slider .slider-handle.is-active .slider-label span {
opacity: 1;
}
@ -873,6 +907,17 @@ input {
background: rgba(255, 255, 255, 0.8);
}
select {
margin: 0 auto 1.2rem auto;
padding: 2px 5px;
width: 100%;
box-sizing: border-box;
border: none;
border-radius: 4px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background: rgba(255, 255, 255, 0.8);
}
input[id^="num"] {
max-width: 6em;
width: auto;
@ -880,3 +925,175 @@ input[id^="num"] {
font-weight: bold;
font-size: 115%;
}
body div>ul.navigation {
margin: 0;
padding: 0;
border-bottom: 3px solid #666;
overflow: hidden;
}
ul.navigation li {
list-style: none;
float: left;
margin-right: 4px;
}
ul.navigation li.controls {
float: right;
}
ul.navigation li a {
font-weight: bold;
display: inline-block;
padding: 6px 12px;
color: #888;
outline: 0;
text-decoration: none;
background: #f3f3f3;
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#eee), to(#e4e4e4));
background: -moz-linear-gradient(#eee, #e4e4e4);
background: linear-gradient(#eee, #e4e4e4);
-pie-background: linear-gradient(#eee, #e4e4e4);
}
ul.navigation li.active a {
pointer-events: none;
color: white;
background: #666;
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#888), to(#666));
background: -moz-linear-gradient(#888, #666);
background: linear-gradient(#888, #666);
-pie-background: linear-gradient(#888, #666);
}
div.tabscontent>div {
padding: 0 15px;
}
#tabsnav:empty {
display: none;
}
.range-slider {
margin: 0 0 0 0;
}
.range-slider {
width: 100%;
}
.range-slider__range {
-webkit-appearance: none;
width: calc(100% - (45px));
height: 10px;
border-radius: 5px;
outline: 0;
padding: 0;
margin: 0;
}
/*
.range-slider__range::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
cursor: pointer;
transition: background 0.15s ease-in-out;
}
.range-slider__range::-webkit-slider-thumb:hover {
background: #1abc9c;
}
.range-slider__range:active::-webkit-slider-thumb {
background: #1abc9c;
}
.range-slider__range::-moz-range-thumb {
width: 20px;
height: 20px;
border: 0;
border-radius: 50%;
cursor: pointer;
transition: background 0.15s ease-in-out;
}
.range-slider__range:focus::-webkit-slider-thumb {
box-shadow: 0 0 0 3px #fff, 0 0 0 6px #1abc9c;
}
*/
.range-slider__value {
display: inline-block;
position: relative;
width: 30px;
color: #fff;
line-height: 20px;
text-align: center;
border-radius: 3px;
padding: 5px 5px;
margin-left: 2px;
}
.range-slider__value:after {
position: absolute;
top: 8px;
left: -7px;
width: 0;
height: 0;
/*border-top:1px solid transparent;
border-right:1px solid #2c3e50;
border-bottom:1px solid transparent;*/
content: "";
}
::-moz-range-track {
border: 0;
}
input::-moz-focus-inner,
input::-moz-focus-outer {
border: 0;
}
/* Styles for Graph widget */
svg {
display: block;
width: 100%;
height: 100%;
}
.y-axis path,
.x-axis path {
stroke: gray;
stroke-width: 1;
fill: none;
}
.series {
stroke: steelblue;
stroke-width: 3;
fill: none;
}
.data-points circle {
stroke: steelblue;
stroke-width: 2;
fill: white;
}
.data-points text {
display: none;
}
.data-points circle:hover {
fill: steelblue;
stroke-width: 6;
}
.data-points circle:hover+text {
display: inline-block;
}
text {
text-anchor: end;
}

1
data/css/style.min.css vendored Normal file

File diff suppressed because one or more lines are too long

35
data/index.htm Normal file
View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Control</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="shortcut icon"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC"
/>
<link rel="stylesheet" href="/css/normalize.css" />
<link rel="stylesheet" href="/css/style.css" />
<script src="/js/zepto.min.js"></script>
<script src="/js/slider.js"></script>
<script src="/js/graph.js"></script>
<script src="/js/controls.js"></script>
<script src="/js/tabbedcontent.js"></script>
</head>
<body onload="javascript:start();">
<div>
<h4>
<div id="mainHeader">Control</div>
<span id="conStatus" class="label">Offline</span>
</h4>
</div>
<hr />
<div class="container">
<div id="row" class="row u-full-width"></div>
<ul id="tabsnav" class="navigation navigation-tabs u-full-width"></ul>
<div id="tabscontent" class="tabscontent u-full-width"></div>
</div>
</body>
</html>

View File

@ -1 +1 @@
<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/controls.js></script></head> <body onload=javascript:start();> <div> <h4><div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span></h4></div> <hr> <div class=container> <div id=row class="row u-full-width"> </div> </div> </body> </html>
<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>

903
data/js/controls.js vendored Normal file
View File

@ -0,0 +1,903 @@
const UI_INITIAL_GUI = 200;
const UI_RELOAD = 201;
const UPDATE_OFFSET = 100;
const UI_TITEL = 0;
const UI_PAD = 1;
const UPDATE_PAD = 101;
const UI_CPAD = 2;
const UPDATE_CPAD = 102;
const UI_BUTTON = 3;
const UPDATE_BUTTON = 103;
const UI_LABEL = 4;
const UPDATE_LABEL = 104;
const UI_SWITCHER = 5;
const UPDATE_SWITCHER = 105;
const UI_SLIDER = 6;
const UPDATE_SLIDER = 106;
const UI_NUMBER = 7;
const UPDATE_NUMBER = 107;
const UI_TEXT_INPUT = 8;
const UPDATE_TEXT_INPUT = 108;
const UI_GRAPH = 9;
const ADD_GRAPH_POINT = 10;
const CLEAR_GRAPH = 109;
const UI_TAB = 11;
const UPDATE_TAB = 111;
const UI_SELECT = 12;
const UPDATE_SELECT = 112;
const UI_OPTION = 13;
const UPDATE_OPTION = 113;
const UI_MIN = 14;
const UPDATE_MIN = 114;
const UI_MAX = 15;
const UPDATE_MAX = 115;
const UI_STEP = 16;
const UPDATE_STEP = 116;
const UI_GAUGE = 17;
const UPDATE_GAUGE = 117;
const UI_ACCEL = 18;
const UPTDATE_ACCEL = 117;
const UP = 0;
const DOWN = 1;
const LEFT = 2;
const RIGHT = 3;
const CENTER = 4;
// Colors
const C_TURQUOISE = 0;
const C_EMERALD = 1;
const C_PETERRIVER = 2;
const C_WETASPHALT = 3;
const C_SUNFLOWER = 4;
const C_CARROT = 5;
const C_ALIZARIN = 6;
const C_DARK = 7;
const C_NONE = 255;
var graphData = new Array();
var hasAccel = false;
var sliderContinuous = false;
function colorClass(colorId) {
colorId = Number(colorId);
switch (colorId) {
case C_TURQUOISE:
return "turquoise";
case C_EMERALD:
return "emerald";
case C_PETERRIVER:
return "peterriver";
case C_WETASPHALT:
return "wetasphalt";
case C_SUNFLOWER:
return "sunflower";
case C_CARROT:
return "carrot";
case C_ALIZARIN:
return "alizarin";
case C_NONE:
return "dark";
default:
return "";
}
}
var websock;
var websockConnected = false;
function requestOrientationPermission() {
/*
// Currently this fails, since it needs secure context on IOS safari
if (typeof DeviceMotionEvent.requestPermission === "function") {
DeviceOrientationEvent.requestPermission()
.then(response => {
if (response == "granted") {
window.addEventListener("deviceorientation", handleOrientation);
}
})
.catch(console.error);
} else {
// Non IOS 13
window.addEventListener("deviceorientation", handleOrientation);
}
*/
}
/*
function handleOrientation(event) {
var x = event.beta; // In degree in the range [-180,180]
var y = event.gamma; // In degree in the range [-90,90]
var output = document.querySelector(".output");
output.innerHTML = "beta : " + x + "\n";
output.innerHTML += "gamma: " + y + "\n";
// Because we don't want to have the device upside down
// We constrain the x value to the range [-90,90]
if (x > 90) {
x = 90;
}
if (x < -90) {
x = -90;
}
// To make computation easier we shift the range of
// x and y to [0,180]
x += 90;
y += 90;
// 10 is half the size of the ball
// It center the positioning point to the center of the ball
var ball = document.querySelector(".ball");
var garden = document.querySelector(".garden");
var maxX = garden.clientWidth - ball.clientWidth;
var maxY = garden.clientHeight - ball.clientHeight;
ball.style.top = (maxY * y) / 180 - 10 + "px";
ball.style.left = (maxX * x) / 180 - 10 + "px";
}
*/
function saveGraphData() {
localStorage.setItem("espuigraphs", JSON.stringify(graphData));
}
function restoreGraphData(id) {
var savedData = localStorage.getItem("espuigraphs", graphData);
if (savedData != null) {
savedData = JSON.parse(savedData);
return savedData[id];
}
return [];
}
function restart() {
$(document).add("*").off();
$("#row").html("");
websock.close();
start();
}
function conStatusError() {
websockConnected = false;
$("#conStatus").removeClass("color-green");
$("#conStatus").addClass("color-red");
$("#conStatus").html("Error / No Connection &#8635;");
$("#conStatus").off();
$("#conStatus").on({
click: restart,
});
}
function handleVisibilityChange() {
if (!websockConnected && !document.hidden) {
restart();
}
}
function start() {
document.addEventListener("visibilitychange", handleVisibilityChange, false);
if (
window.location.port != "" ||
window.location.port != 80 ||
window.location.port != 443
) {
websock = new WebSocket(
"ws://" + window.location.hostname + ":" + window.location.port + "/ws"
);
} else {
websock = new WebSocket("ws://" + window.location.hostname + "/ws");
}
websock.onopen = function (evt) {
console.log("websock open");
$("#conStatus").addClass("color-green");
$("#conStatus").text("Connected");
websockConnected = true;
};
websock.onclose = function (evt) {
console.log("websock close");
conStatusError();
};
websock.onerror = function (evt) {
console.log(evt);
conStatusError();
};
var handleEvent = function (evt) {
console.log(evt);
var data = JSON.parse(evt.data);
var e = document.body;
var center = "";
switch (data.type) {
case UI_INITIAL_GUI:
// Clear current elements
$("#row").html("");
$("#tabsnav").html("");
$("#tabscontent").html("");
if (data.sliderContinuous) {
sliderContinuous = data.sliderContinuous;
}
data.controls.forEach(element => {
var fauxEvent = {
data: JSON.stringify(element),
};
handleEvent(fauxEvent);
});
break;
case UI_RELOAD:
window.location.reload();
break;
case UI_TITEL:
document.title = data.label;
$("#mainHeader").html(data.label);
break;
case UI_LABEL:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<span id='l" +
data.id +
"' class='label label-wrap'>" +
data.value +
"</span>" +
"</div>"
);
break;
case UI_BUTTON:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='one columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<button id='btn" +
data.id +
"' " +
"onmousedown='buttonclick(" +
data.id +
", true)' " +
"onmouseup='buttonclick(" +
data.id +
", false)'>" +
data.value +
"</button></div>"
);
$("#btn" + data.id).on({
touchstart: function (e) {
e.preventDefault();
buttonclick(data.id, true);
},
touchend: function (e) {
e.preventDefault();
buttonclick(data.id, false);
},
});
break;
case UI_SWITCHER:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='one columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<label id='sl" +
data.id +
"' class='switch " +
(data.value == "1" ? "checked" : "") +
"'>" +
"<div class='in'><input type='checkbox' id='s" +
data.id +
"' onClick='switcher(" +
data.id +
",null)' " +
(data.value == "1" ? "checked" : "") +
"/></div>" +
"</label>" +
"</div>"
);
switcher(data.id, data.value);
break;
case UI_CPAD:
case UI_PAD:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<nav class='control'>" +
"<ul>" +
"<li><a onmousedown='padclick(UP, " +
data.id +
", true)' onmouseup='padclick(UP, " +
data.id +
", false)' id='pf" +
data.id +
"'>▲</a></li>" +
"<li><a onmousedown='padclick(RIGHT, " +
data.id +
", true)' onmouseup='padclick(RIGHT, " +
data.id +
", false)' id='pr" +
data.id +
"'>▲</a></li>" +
"<li><a onmousedown='padclick(LEFT, " +
data.id +
", true)' onmouseup='padclick(LEFT, " +
data.id +
", false)' id='pl" +
data.id +
"'>▲</a></li>" +
"<li><a onmousedown='padclick(DOWN, " +
data.id +
", true)' onmouseup='padclick(DOWN, " +
data.id +
", false)' id='pb" +
data.id +
"'>▲</a></li>" +
"</ul>" +
(data.type == UI_CPAD
? "<a class='confirm' onmousedown='padclick(CENTER," +
data.id +
", true)' onmouseup='padclick(CENTER, " +
data.id +
", false)' id='pc" +
data.id +
"'>OK</a>"
: "") +
"</nav>" +
"</div>"
);
$("#pf" + data.id).on({
touchstart: function (e) {
e.preventDefault();
padclick(UP, data.id, true);
},
touchend: function (e) {
e.preventDefault();
padclick(UP, data.id, false);
},
});
$("#pl" + data.id).on({
touchstart: function (e) {
e.preventDefault();
padclick(LEFT, data.id, true);
},
touchend: function (e) {
e.preventDefault();
padclick(LEFT, data.id, false);
},
});
$("#pr" + data.id).on({
touchstart: function (e) {
e.preventDefault();
padclick(RIGHT, data.id, true);
},
touchend: function (e) {
e.preventDefault();
padclick(RIGHT, data.id, false);
},
});
$("#pb" + data.id).on({
touchstart: function (e) {
e.preventDefault();
padclick(DOWN, data.id, true);
},
touchend: function (e) {
e.preventDefault();
padclick(DOWN, data.id, false);
},
});
$("#pc" + data.id).on({
touchstart: function (e) {
e.preventDefault();
padclick(CENTER, data.id, true);
},
touchend: function (e) {
e.preventDefault();
padclick(CENTER, data.id, false);
},
});
break;
//https://codepen.io/seanstopnik/pen/CeLqA
case UI_SLIDER:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter card-slider " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<div class='range-slider'>" +
"<input id='sl" +
data.id +
"' type='range' min='0' max='100' value='" +
data.value +
"' class='range-slider__range'>" +
"<span class='range-slider__value'>" +
data.value +
"</span>" +
"</div>" +
"</div>"
);
rangeSlider(!sliderContinuous);
break;
case UI_NUMBER:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<input style='color:black;' id='num" +
data.id +
"' type='number' value='" +
data.value +
"' onchange='numberchange(" +
data.id +
")' />" +
"</div>"
);
break;
case UI_TEXT_INPUT:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<input style='color:black;' id='text" +
data.id +
"' value='" +
data.value +
"' onchange='textchange(" +
data.id +
")' />" +
"</div>"
);
break;
case UI_TAB:
$("#tabsnav").append(
"<li><a onmouseup='tabclick(" + data.id + ")' href='#tab" + data.id + "'>" + data.value + "</a></li>"
);
$("#tabscontent").append("<div id='tab" + data.id + "'></div>");
tabs = $(".tabscontent").tabbedContent({ loop: true }).data("api");
// switch to tab...
$("a")
.filter(function () {
return $(this).attr("href") === "#click-to-switch";
})
.on("click", function (e) {
var tab = prompt("Tab to switch to (number or id)?");
if (!tabs.switchTab(tab)) {
alert("That tab does not exist :\\");
}
e.preventDefault();
});
break;
case UI_SELECT:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<select style='color:black;' id='select" +
data.id +
"' onchange='selectchange(" +
data.id +
")' />" +
"</div>"
);
break;
case UI_OPTION:
if (data.parentControl) {
var parent = $("#select" + data.parentControl);
parent.append(
"<option id='option" +
data.id +
"' value='" +
data.value +
"' " +
data.selected +
">" +
data.label +
"</option>"
);
}
break;
case UI_MIN:
if (data.parentControl) {
var parent = $("#id" + data.parentControl + " input");
if (parent.size()) {
parent.attr("min", data.value);
}
}
break;
case UI_MAX:
if (data.parentControl) {
var parent = $("#id" + data.parentControl + " input");
if (parent.size()) {
parent.attr("max", data.value);
}
}
break;
case UI_STEP:
if (data.parentControl) {
var parent = $("#id" + data.parentControl + " input");
if (parent.size()) {
parent.attr("step", data.value);
}
}
break;
case UI_GRAPH:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"<figure id='graph" +
data.id +
"'>" +
"<figcaption>" +
data.label +
"</figcaption>" +
"</figure>" +
"</div>"
);
graphData[data.id] = restoreGraphData(data.id);
renderGraphSvg(graphData[data.id], "graph" + data.id);
break;
case ADD_GRAPH_POINT:
var ts = Math.round(new Date().getTime() / 1000);
graphData[data.id].push({ x: ts, y: data.value });
saveGraphData();
renderGraphSvg(graphData[data.id], "graph" + data.id);
break;
case CLEAR_GRAPH:
graphData[data.id] = [];
saveGraphData();
renderGraphSvg(graphData[data.id], "graph" + data.id);
break;
case UI_GAUGE:
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"WILL BE A GAUGE <input style='color:black;' id='gauge" +
data.id +
"' type='number' value='" +
data.value +
"' onchange='numberchange(" +
data.id +
")' />" +
"</div>"
);
break;
case UI_ACCEL:
if (hasAccel) break;
var parent;
if (data.parentControl) {
parent = $("#tab" + data.parentControl);
} else {
parent = $("#row");
}
hasAccel = true;
parent.append(
"<div id='id" +
data.id +
"' class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5>" +
data.label +
"</h5><hr/>" +
"ACCEL // Not implemented fully!<div class='accelerometer' id='accel" +
data.id +
"' ><div class='ball" +
data.id +
"'></div><pre class='accelerometeroutput" +
data.id +
"'></pre>" +
"</div>"
);
requestOrientationPermission();
break;
case UPDATE_LABEL:
$("#l" + data.id).html(data.value);
break;
case UPDATE_SWITCHER:
switcher(data.id, data.value == "0" ? 0 : 1);
break;
case UPDATE_SLIDER:
slider_move($("#id" + data.id), data.value, "100", false);
break;
case UPDATE_NUMBER:
$("#num" + data.id).val(data.value);
break;
case UPDATE_TEXT_INPUT:
$("#text" + data.id).val(data.value);
break;
case UPDATE_SELECT:
$("#select" + data.id).val(data.value);
break;
case UPDATE_BUTTON:
case UPDATE_PAD:
case UPDATE_CPAD:
break;
case UPDATE_GAUGE:
$("#gauge" + data.id).val(data.value);
break;
case UPDATE_ACCEL:
break;
default:
console.error("Unknown type or event");
break;
}
if (data.type >= UPDATE_OFFSET && data.type < UI_INITIAL_GUI) {
var element = $("#id" + data.id);
if (data.type == UPDATE_SLIDER) {
element.removeClass(
"slider-turquoise slider-emerald slider-peterriver slider-wetasphalt slider-sunflower slider-carrot slider-alizarin"
);
element.addClass("slider-" + colorClass(data.color));
} else {
element.removeClass(
"turquoise emerald peterriver wetasphalt sunflower carrot alizarin"
);
element.addClass(colorClass(data.color));
}
}
};
websock.onmessage = handleEvent;
}
function sliderchange(number) {
var val = $("#sl" + number).val();
websock.send("slvalue:" + val + ":" + number);
}
function numberchange(number) {
var val = $("#num" + number).val();
websock.send("nvalue:" + val + ":" + number);
}
function textchange(number) {
var val = $("#text" + number).val();
websock.send("tvalue:" + val + ":" + number);
}
function tabclick(number) {
var val = $("#tab" + number).val();
websock.send("tabvalue:" + val + ":" + number);
}
function selectchange(number) {
var val = $("#select" + number).val();
websock.send("svalue:" + val + ":" + number);
}
function buttonclick(number, isdown) {
if (isdown) websock.send("bdown:" + number);
else websock.send("bup:" + number);
}
function padclick(type, number, isdown) {
switch (type) {
case CENTER:
if (isdown) websock.send("pcdown:" + number);
else websock.send("pcup:" + number);
break;
case UP:
if (isdown) websock.send("pfdown:" + number);
else websock.send("pfup:" + number);
break;
case DOWN:
if (isdown) websock.send("pbdown:" + number);
else websock.send("pbup:" + number);
break;
case LEFT:
if (isdown) websock.send("pldown:" + number);
else websock.send("plup:" + number);
break;
case RIGHT:
if (isdown) websock.send("prdown:" + number);
else websock.send("prup:" + number);
break;
}
}
function switcher(number, state) {
if (state == null) {
if ($("#s" + number).is(":checked")) {
websock.send("sactive:" + number);
$("#sl" + number).addClass("checked");
} else {
websock.send("sinactive:" + number);
$("#sl" + number).removeClass("checked");
}
} else if (state == 1) {
$("#sl" + number).addClass("checked");
$("#sl" + number).prop("checked", true);
} else if (state == 0) {
$("#sl" + number).removeClass("checked");
$("#sl" + number).prop("checked", false);
}
}
var rangeSlider = function (isDiscrete) {
var slider = $(".range-slider"),
range = $(".range-slider__range"),
value = $(".range-slider__value");
slider.each(function () {
value.each(function () {
var value = $(this).prev().attr("value");
$(this).html(value);
});
if (!isDiscrete) {
range.on({
input: function () {
sliderchange($(this).attr("id").replace(/^\D+/g, ""));
},
});
} else {
range.on({
input: function () {
$(this).next().html(this.value);
},
change: function () {
sliderchange($(this).attr("id").replace(/^\D+/g, ""));
},
});
}
});
};

1
data/js/controls.min.js vendored Normal file

File diff suppressed because one or more lines are too long

297
data/js/graph.js Normal file
View File

@ -0,0 +1,297 @@
function lineGraph(parent, xAccessor, yAccessor) {
// Constant size definitions TODO: this could well be improved and calculated...
const width = 620;
const height = 420;
const gutter = 40;
const pixelsPerTick = 30;
/**
* Creates an object that contatins transform functions that:
* transforms numeric data into coordinate space, linearly
* transforms coordinates into numeric data, linearly
*/
function numericTransformer(dataMin, dataMax, pxMin, pxMax) {
var dataDiff = dataMax - dataMin,
pxDiff = pxMax - pxMin,
dataRatio = pxDiff / dataDiff,
coordRatio = dataDiff / pxDiff;
return {
// transforms a data point to a coordinate point
toCoord: function(data) {
return (data - dataMin) * dataRatio + pxMin;
},
// transforms a coord point to a data point
toData: function(coord) {
return (coord - pxMin) * coordRatio + dataMin;
}
};
}
/**
* Renders an axis.
* orientation = 'x' or 'y'
* transform = a function for transforming px into data for labeling/creating tick marks
*/
function axisRenderer(orientation, transform) {
var axisGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
var axisPath = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
);
axisGroup.setAttribute("class", orientation + "-axis");
var xMin = gutter;
var xMax = width - gutter;
var yMin = height - gutter;
var yMax = gutter;
if (orientation === "x") {
axisPath.setAttribute(
"d",
"M " + xMin + " " + yMin + " L " + xMax + " " + yMin
);
// generate labels
for (var i = xMin; i <= xMax; i++) {
if ((i - xMin) % pixelsPerTick === 0 && i !== xMin) {
var text = document.createElementNS(
"http://www.w3.org/2000/svg",
"text"
);
// primitive formatting
text.innerHTML = Math.floor(transform(i));
text.setAttribute("x", i);
text.setAttribute("y", yMin);
// offset the text by 1 em
text.setAttribute("dy", "1em");
axisGroup.appendChild(text);
}
}
} else {
axisPath.setAttribute(
"d",
"M " + xMin + " " + yMin + " L " + xMin + " " + yMax
);
// generate labels
for (var i = yMax; i <= yMin; i++) {
if ((i - yMin) % pixelsPerTick === 0 && i !== yMin) {
var tickGroup = document.createElementNS(
"http://www.w3.org/2000/svg",
"g"
);
var gridLine = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
);
text = document.createElementNS("http://www.w3.org/2000/svg", "text");
// primitive formatting
text.innerHTML = Math.floor(transform(i));
text.setAttribute("x", xMin);
text.setAttribute("y", i);
// offset the text labels to align with grid line and keeping it to the left of the y-axis
text.setAttribute("dx", "-.5em");
text.setAttribute("dy", ".3em");
gridLine.setAttribute(
"d",
"M " + xMin + " " + i + " L " + xMax + " " + i
);
tickGroup.appendChild(gridLine);
tickGroup.appendChild(text);
axisGroup.appendChild(tickGroup);
}
}
}
axisGroup.appendChild(axisPath);
parent.appendChild(axisGroup);
}
/**
* Renders a line
*/
function lineRenderer(xAccessor, yAccessor, xTransform, yTransform) {
var line = document.createElementNS("http://www.w3.org/2000/svg", "path");
xAccessor.reset();
yAccessor.reset();
if (!xAccessor.hasNext() || !yAccessor.hasNext()) {
return;
}
var pathString =
"M " + xTransform(xAccessor.next()) + " " + yTransform(yAccessor.next());
while (xAccessor.hasNext() && yAccessor.hasNext()) {
pathString +=
" L " +
xTransform(xAccessor.next()) +
" " +
yTransform(yAccessor.next());
}
line.setAttribute("class", "series");
line.setAttribute("d", pathString);
parent.appendChild(line);
}
/**
* Renders data point circles + text labels
*/
function pointRenderer(xAccessor, yAccessor, xTransform, yTransform) {
var pointGroup = document.createElementNS(
"http://www.w3.org/2000/svg",
"g"
);
pointGroup.setAttribute("class", "data-points");
xAccessor.reset();
yAccessor.reset();
if (!xAccessor.hasNext() || !yAccessor.hasNext()) {
return;
}
while (xAccessor.hasNext() && yAccessor.hasNext()) {
var xDataValue = xAccessor.next();
var x = xTransform(xDataValue);
var yDataValue = yAccessor.next();
var y = yTransform(yDataValue);
var circle = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle"
);
circle.setAttribute("cx", x);
circle.setAttribute("cy", y);
circle.setAttribute("r", "4");
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
// primitive formatting
text.innerHTML = Math.floor(xDataValue) + " / " + Math.floor(yDataValue);
text.setAttribute("x", x);
text.setAttribute("y", y);
text.setAttribute("dx", "1em");
text.setAttribute("dy", "-.7em");
pointGroup.appendChild(circle);
pointGroup.appendChild(text);
}
parent.appendChild(pointGroup);
}
// perform the rendering
xTransform = numericTransformer(
xAccessor.min(),
xAccessor.max(),
0 + gutter,
width - gutter
);
// NOTE: for y... have to reverse coordinate space
yTransform = numericTransformer(
yAccessor.min(),
yAccessor.max(),
height - gutter,
0 + gutter
);
axisRenderer("x", xTransform.toData);
axisRenderer("y", yTransform.toData);
lineRenderer(xAccessor, yAccessor, xTransform.toCoord, yTransform.toCoord);
pointRenderer(xAccessor, yAccessor, xTransform.toCoord, yTransform.toCoord);
}
// Final render function
function renderGraphSvg(dataArray, renderId) {
var figure = document.getElementById(renderId);
while (figure.hasChildNodes()) {
figure.removeChild(figure.lastChild);
}
//console.log(dataArray);
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("viewBox", "0 0 640 440");
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
lineGraph(
svg,
// time accessor
(function(data, min, max) {
var i = 0;
return {
hasNext: function() {
return i < data.length;
},
next: function() {
return data[i++].x;
},
reset: function() {
i = 0;
},
min: function() {
return min;
},
max: function() {
return max;
}
};
})(
dataArray,
Math.min.apply(
Math,
dataArray.map(function(o) {
return o.x;
})
),
Math.max.apply(
Math,
dataArray.map(function(o) {
return o.x;
})
)
),
// value accessor
(function(data, min, max) {
var i = 0;
return {
hasNext: function() {
return i < data.length;
},
next: function() {
return data[i++].y;
},
reset: function() {
i = 0;
},
min: function() {
return min;
},
max: function() {
return max;
}
};
})(
dataArray,
Math.min.apply(
Math,
dataArray.map(function(o) {
return o.y;
})
),
Math.max.apply(
Math,
dataArray.map(function(o) {
return o.y;
})
)
)
);
figure.appendChild(svg);
}

15
data/js/graph.min.js vendored Normal file
View File

@ -0,0 +1,15 @@
function lineGraph(parent,xAccessor,yAccessor){const width=620;const height=420;const gutter=40;const pixelsPerTick=30;function numericTransformer(dataMin,dataMax,pxMin,pxMax){var dataDiff=dataMax-dataMin,pxDiff=pxMax-pxMin,dataRatio=pxDiff/dataDiff,coordRatio=dataDiff/pxDiff;return{toCoord:function(data){return(data-dataMin)*dataRatio+pxMin;},toData:function(coord){return(coord-pxMin)*coordRatio+dataMin;}};}
function axisRenderer(orientation,transform){var axisGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var axisPath=document.createElementNS("http://www.w3.org/2000/svg","path");axisGroup.setAttribute("class",orientation+"-axis");var xMin=gutter;var xMax=width-gutter;var yMin=height-gutter;var yMax=gutter;if(orientation==="x"){axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMax+" "+yMin);for(var i=xMin;i<=xMax;i++){if((i-xMin)%pixelsPerTick===0&&i!==xMin){var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",i);text.setAttribute("y",yMin);text.setAttribute("dy","1em");axisGroup.appendChild(text);}}}else{axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMin+" "+yMax);for(var i=yMax;i<=yMin;i++){if((i-yMin)%pixelsPerTick===0&&i!==yMin){var tickGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var gridLine=document.createElementNS("http://www.w3.org/2000/svg","path");text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",xMin);text.setAttribute("y",i);text.setAttribute("dx","-.5em");text.setAttribute("dy",".3em");gridLine.setAttribute("d","M "+xMin+" "+i+" L "+xMax+" "+i);tickGroup.appendChild(gridLine);tickGroup.appendChild(text);axisGroup.appendChild(tickGroup);}}}
axisGroup.appendChild(axisPath);parent.appendChild(axisGroup);}
function lineRenderer(xAccessor,yAccessor,xTransform,yTransform){var line=document.createElementNS("http://www.w3.org/2000/svg","path");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
var pathString="M "+xTransform(xAccessor.next())+" "+yTransform(yAccessor.next());while(xAccessor.hasNext()&&yAccessor.hasNext()){pathString+=" L "+
xTransform(xAccessor.next())+
" "+
yTransform(yAccessor.next());}
line.setAttribute("class","series");line.setAttribute("d",pathString);parent.appendChild(line);}
function pointRenderer(xAccessor,yAccessor,xTransform,yTransform){var pointGroup=document.createElementNS("http://www.w3.org/2000/svg","g");pointGroup.setAttribute("class","data-points");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
while(xAccessor.hasNext()&&yAccessor.hasNext()){var xDataValue=xAccessor.next();var x=xTransform(xDataValue);var yDataValue=yAccessor.next();var y=yTransform(yDataValue);var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");circle.setAttribute("cx",x);circle.setAttribute("cy",y);circle.setAttribute("r","4");var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(xDataValue)+" / "+Math.floor(yDataValue);text.setAttribute("x",x);text.setAttribute("y",y);text.setAttribute("dx","1em");text.setAttribute("dy","-.7em");pointGroup.appendChild(circle);pointGroup.appendChild(text);}
parent.appendChild(pointGroup);}
xTransform=numericTransformer(xAccessor.min(),xAccessor.max(),0+gutter,width-gutter);yTransform=numericTransformer(yAccessor.min(),yAccessor.max(),height-gutter,0+gutter);axisRenderer("x",xTransform.toData);axisRenderer("y",yTransform.toData);lineRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);pointRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);}
function renderGraphSvg(dataArray,renderId){var figure=document.getElementById(renderId);while(figure.hasChildNodes()){figure.removeChild(figure.lastChild);}
var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 640 440");svg.setAttribute("preserveAspectRatio","xMidYMid meet");lineGraph(svg,(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].x;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.x;})),Math.max.apply(Math,dataArray.map(function(o){return o.x;}))),(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].y;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.y;})),Math.max.apply(Math,dataArray.map(function(o){return o.y;}))));figure.appendChild(svg);}

123
data/js/slider.js Normal file
View File

@ -0,0 +1,123 @@
/* -----------------------------------------------------
Material Design Sliders
CodePen URL: https://codepen.io/rkchauhan/pen/xVGGpR
By: Ravikumar Chauhan
-------------------------------------------------------- */
function rkmd_rangeSlider(selector) {
var self, slider_width, slider_offset, curnt, sliderDiscrete, range, slider;
self = $(selector);
slider_width = self.width();
slider_offset = self.offset().left;
sliderDiscrete = self;
sliderDiscrete.each(function (i, v) {
curnt = $(this);
curnt.append(sliderDiscrete_tmplt());
range = curnt.find('input[type="range"]');
slider = curnt.find(".slider");
slider_fill = slider.find(".slider-fill");
slider_handle = slider.find(".slider-handle");
slider_label = slider.find(".slider-label");
var range_val = parseInt(range.val());
slider_fill.css("width", range_val + "%");
slider_handle.css("left", range_val + "%");
slider_label.find("span").text(range_val);
});
self.on("mousedown touchstart", ".slider-handle", function (e) {
if (e.button === 2) {
return false;
}
var parents = $(this).parents(".rkmd-slider");
var slider_width = parents.width();
var slider_offset = parents.offset().left;
var check_range = parents.find('input[type="range"]').is(":disabled");
if (check_range === true) {
return false;
}
$(this).addClass("is-active");
var moveFu = function (e) {
var pageX = e.pageX || e.changedTouches[0].pageX;
var slider_new_width = pageX - slider_offset;
if (slider_new_width <= slider_width && !(slider_new_width < "0")) {
slider_move(parents, slider_new_width, slider_width, true);
}
};
var upFu = function (e) {
$(this).off(handlers);
parents.find(".is-active").removeClass("is-active");
};
var handlers = {
mousemove: moveFu,
touchmove: moveFu,
mouseup: upFu,
touchend: upFu,
};
$(document).on(handlers);
});
self.on("mousedown touchstart", ".slider", function (e) {
if (e.button === 2) {
return false;
}
var parents = $(this).parents(".rkmd-slider");
var slider_width = parents.width();
var slider_offset = parents.offset().left;
var check_range = parents.find('input[type="range"]').is(":disabled");
if (check_range === true) {
return false;
}
var slider_new_width = e.pageX - slider_offset;
if (slider_new_width <= slider_width && !(slider_new_width < "0")) {
slider_move(parents, slider_new_width, slider_width, true);
}
var upFu = function (e) {
$(this).off(handlers);
};
var handlers = {
mouseup: upFu,
touchend: upFu,
};
$(document).on(handlers);
});
}
function sliderDiscrete_tmplt() {
var tmplt =
'<div class="slider">' +
'<div class="slider-fill"></div>' +
'<div class="slider-handle"><div class="slider-label"><span>0</span></div></div>' +
"</div>";
return tmplt;
}
function slider_move(parents, newW, sliderW, send) {
var slider_new_val = parseInt(Math.round((newW / sliderW) * 100));
var slider_fill = parents.find(".slider-fill");
var slider_handle = parents.find(".slider-handle");
var range = parents.find('input[type="range"]');
range.next().html(newW); // update value
slider_fill.css("width", slider_new_val + "%");
slider_handle.css({
left: slider_new_val + "%",
transition: "none",
"-webkit-transition": "none",
"-moz-transition": "none",
});
range.val(slider_new_val);
if (parents.find(".slider-handle span").text() != slider_new_val) {
parents.find(".slider-handle span").text(slider_new_val);
var number = parents.attr("id").substring(2);
if (send) websock.send("slvalue:" + slider_new_val + ":" + number);
}
}

11
data/js/slider.min.js vendored Normal file
View File

@ -0,0 +1,11 @@
function rkmd_rangeSlider(selector){var self,slider_width,slider_offset,curnt,sliderDiscrete,range,slider;self=$(selector);slider_width=self.width();slider_offset=self.offset().left;sliderDiscrete=self;sliderDiscrete.each(function(i,v){curnt=$(this);curnt.append(sliderDiscrete_tmplt());range=curnt.find('input[type="range"]');slider=curnt.find(".slider");slider_fill=slider.find(".slider-fill");slider_handle=slider.find(".slider-handle");slider_label=slider.find(".slider-label");var range_val=parseInt(range.val());slider_fill.css("width",range_val+"%");slider_handle.css("left",range_val+"%");slider_label.find("span").text(range_val);});self.on("mousedown touchstart",".slider-handle",function(e){if(e.button===2){return false;}
var parents=$(this).parents(".rkmd-slider");var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(":disabled");if(check_range===true){return false;}
$(this).addClass("is-active");var moveFu=function(e){var pageX=e.pageX||e.changedTouches[0].pageX;var slider_new_width=pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<"0")){slider_move(parents,slider_new_width,slider_width,true);}};var upFu=function(e){$(this).off(handlers);parents.find(".is-active").removeClass("is-active");};var handlers={mousemove:moveFu,touchmove:moveFu,mouseup:upFu,touchend:upFu,};$(document).on(handlers);});self.on("mousedown touchstart",".slider",function(e){if(e.button===2){return false;}
var parents=$(this).parents(".rkmd-slider");var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(":disabled");if(check_range===true){return false;}
var slider_new_width=e.pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<"0")){slider_move(parents,slider_new_width,slider_width,true);}
var upFu=function(e){$(this).off(handlers);};var handlers={mouseup:upFu,touchend:upFu,};$(document).on(handlers);});}
function sliderDiscrete_tmplt(){var tmplt='<div class="slider">'+
'<div class="slider-fill"></div>'+
'<div class="slider-handle"><div class="slider-label"><span>0</span></div></div>'+
"</div>";return tmplt;}
function slider_move(parents,newW,sliderW,send){var slider_new_val=parseInt(Math.round((newW/sliderW)*100));var slider_fill=parents.find(".slider-fill");var slider_handle=parents.find(".slider-handle");var range=parents.find('input[type="range"]');range.next().html(newW);slider_fill.css("width",slider_new_val+"%");slider_handle.css({left:slider_new_val+"%",transition:"none","-webkit-transition":"none","-moz-transition":"none",});range.val(slider_new_val);if(parents.find(".slider-handle span").text()!=slider_new_val){parents.find(".slider-handle span").text(slider_new_val);var number=parents.attr("id").substring(2);if(send)websock.send("slvalue:"+slider_new_val+":"+number);}}

351
data/js/tabbedcontent.js Normal file
View File

@ -0,0 +1,351 @@
/**
* Tabs plugin for jQuery created by Òscar Casajuana < elboletaire at underave dot net >
*
* @copyright Copyright 2013-2016 Òscar Casajuana
* @license MIT
* @author Òscar Casajuana Alonso <elboletaire at underave dot net>
*/
;(function($, document, window, undefined) {
"use strict";
var Tabbedcontent = function(tabcontent, options) {
var defaults = {
links : tabcontent.prev().find('a').length ? tabcontent.prev().find('a') : '.tabs a', // the tabs itself. By default it selects the links contained in the previous wrapper or the links inside ".tabs a" if there's no previous item
errorSelector : '.error-message', // false to disable
speed : false, // speed of the show effect. Set to null or false to disable
onSwitch : false, // onSwitch callback
onInit : false, // onInit callback
currentClass : 'active', // current selected tab class (is set to the <a> element)
tabErrorClass : 'has-errors', // a class to be added to the tab where errorSelector is detected
history : true, // set to false to disable HTML5 history
historyOnInit : true, // allows to deactivate the history for the intial autmatically tab switch on load
loop : false // if set to true will loop between tabs when using the next() and prev() api methods
},
firstTime = false,
children = tabcontent.children(),
history = window.history,
loc = document.location,
current = null
;
options = $.extend(defaults, options);
if (!(options.links instanceof $)) {
options.links = $(options.links);
}
/**
* Checks if the specified tab id exists.
*
* @param string tab Tab #id
* @return bool
*/
function tabExists(tab) {
return Boolean(children.filter(tab).length);
}
/**
* Checks if the current tab is the
* first one in the tabs set.
*
* @return bool
*/
function isFirst() {
return current === 0;
}
/**
* Checks if the passed number is an integer.
*
* @param mixed num The value to be checked.
* @return bool
*/
function isInt(num) {
return num % 1 === 0;
}
/**
* Checks if the current tab is the
* last one in the tabs set.
*
* @return {Boolean} [description]
*/
function isLast() {
return current === children.length - 1;
}
/**
* Filters a tab based on current links href.
*
* Method for compatibility with Zepto.js
*
* @param string tab Tab #href
* @return bool
*/
function filterTab(tab) {
return $(this).attr('href').match(new RegExp(tab + '$'));
}
/**
* Returns an object containing two jQuery instances:
* one for the tab content and the other for its link.
*
* @param mixed tab A tab id, #id or index.
* @return object With thi
*/
function getTab(tab) {
if (tab instanceof $) {
return {
tab : tab,
link : options.links.eq(tab.index())
};
}
if (isInt(tab)) {
return {
tab : children.eq(tab),
link : options.links.eq(tab)
};
}
if (children.filter(tab).length) {
return {
tab : children.filter(tab),
link : options.links.filter(function() {
return filterTab.apply(this, [tab]);
})
};
}
// assume it's an id without #
return {
tab : children.filter('#' + tab),
link : options.links.filter(function() {
return filterTab.apply(this, ['#' + tab]);
})
};
}
/**
* Returns the index of the current tab.
*
* @return int
*/
function getCurrent() {
return options.links.parent().filter('.' + options.currentClass).index();
}
/**
* Go to the next tab in the tabs set.
*
* @param bool loop If defined will overwrite options.loop
* @return mixed
*/
function next(loop) {
++current;
if (loop === undefined) loop = options.loop;
if (current < children.length) {
return switchTab(current, true);
} else if (loop && current >= children.length) {
return switchTab(0, true);
}
return false;
}
/**
* Go to the previous tab in the tabs set.
*
* @param bool loop If defined will overwrite options.loop
* @return mixed
*/
function prev(loop) {
--current;
if (loop === undefined) loop = options.loop;
if (current >= 0) {
return switchTab(current, true);
} else if (loop && current < 0) {
return switchTab(children.length - 1, true);
}
return false;
}
/**
* onSwitch callback for switchTab.
*
* @param string tab The tab #id
* @return void
*/
function onSwitch(tab) {
if (options.history && options.historyOnInit && firstTime && history !== undefined && ('pushState' in history)) {
firstTime = false;
window.setTimeout(function() {
history.replaceState(null, '', tab);
}, 100);
}
current = getCurrent();
if (options.onSwitch && typeof options.onSwitch === 'function') {
options.onSwitch(tab, api());
}
tabcontent.trigger('tabcontent.switch', [tab, api()]);
}
/**
* Switch to specified tab.
*
* @param mixed tab The tab to switch to.
* @param bool api Set to true to force history writing.
* @return bool Returns false if tab does not exist; true otherwise.
*/
function switchTab(tab, api) {
if (!tab.toString().match(/^#/)) {
tab = '#' + getTab(tab).tab.attr('id');
}
if (!tabExists(tab)) {
return false;
}
// Toggle active class
options.links.attr('aria-selected','false').parent().removeClass(options.currentClass);
options.links.filter(function() {
return filterTab.apply(this, [tab]);
}).attr('aria-selected','true').parent().addClass(options.currentClass);
// Hide tabs
children.hide();
// We need to force the change of the hash if we're using the API
if (options.history && api) {
if (history !== undefined && ('pushState' in history)) {
history.pushState(null, '', tab);
} else {
// force hash change to add it to the history
window.location.hash = tab;
}
}
// Show tabs
children.attr('aria-hidden','true').filter(tab).show(options.speed, function() {
if (options.speed) {
onSwitch(tab);
}
}).attr('aria-hidden','false');
if (!options.speed) {
onSwitch(tab);
}
return true;
}
/**
* Api method to switch tabs.
*
* @param mixed tab Tab to switch to.
* @return bool Returns false if tab does not exist; true otherwise.
*/
function apiSwitch(tab) {
return switchTab(tab, true);
}
/**
* Method used to switch tabs using the
* browser query hash.
*
* @param object e Event.
* @return void
*/
function hashSwitch(e) {
switchTab(loc.hash);
}
/**
* Initialization method.
*
* The tab checking preference is:
* - document.location.hash
* - options.errorSelector
* - first tab in the set of tabs
*
* The onInit method is called at the
* end of this method.
*
* @return void
*/
function init() {
// Switch to tab using location.hash
if (tabExists(loc.hash)) {
// Switch to current hash tab
switchTab(loc.hash);
}
// If there's a tab link with the options.currentClass set,
// switch to that tab.
else if (options.links.parent().filter('.' + options.currentClass).length) {
switchTab(options.links.parent().filter('.' + options.currentClass).index());
}
// Switch to tab containing class options.errorSelector
else if (options.errorSelector && children.find(options.errorSelector).length) {
// Search for errors and show first tab containing one
children.each(function() {
if ($(this).find(options.errorSelector).length) {
switchTab("#" + $(this).attr("id"));
return false;
}
});
}
// Open first tab
else {
switchTab("#" + children.filter(":first-child").attr("id"));
}
// Add a class to every tab containing errors
if (options.errorSelector) {
children.find(options.errorSelector).each(function() {
var tab = getTab($(this).parent());
tab.link.parent().addClass(options.tabErrorClass);
});
}
// Binding
if ('onhashchange' in window) {
$(window).bind('hashchange', hashSwitch);
} else { // old browsers
var current_href = loc.href;
window.setInterval(function() {
if (current_href !== loc.href) {
hashSwitch.call(window.event);
current_href = loc.href;
}
}, 100);
}
// Bind click event on links, to ensure we don't rewrite the URI in
// case history is disabled
$(options.links).on('click', function(e) {
switchTab($(this).attr('href').replace(/^[^#]+/, ''), options.history);
e.preventDefault();
});
// onInit callback
if (options.onInit && typeof options.onInit === 'function') {
options.onInit(api());
}
tabcontent.trigger('tabcontent.init', [api()]);
}
/**
* Returns the methods exposed in the api.
*
* @return object Containing each api method.
*/
function api() {
return {
'switch' : apiSwitch,
'switchTab' : apiSwitch, // for old browsers
'getCurrent' : getCurrent,
'getTab' : getTab,
'next' : next,
'prev' : prev,
'isFirst' : isFirst,
'isLast' : isLast
};
}
init();
return api();
};
$.fn.tabbedContent = function(options) {
return this.each(function() {
var tabs = new Tabbedcontent($(this), options);
$(this).data('api', tabs);
});
};
})(window.jQuery || window.Zepto || window.$, document, window);

35
data/js/tabbedcontent.min.js vendored Normal file
View File

@ -0,0 +1,35 @@
;(function($,document,window,undefined){"use strict";var Tabbedcontent=function(tabcontent,options){var defaults={links:tabcontent.prev().find('a').length?tabcontent.prev().find('a'):'.tabs a',errorSelector:'.error-message',speed:false,onSwitch:false,onInit:false,currentClass:'active',tabErrorClass:'has-errors',history:true,historyOnInit:true,loop:false},firstTime=false,children=tabcontent.children(),history=window.history,loc=document.location,current=null;options=$.extend(defaults,options);if(!(options.links instanceof $)){options.links=$(options.links);}
function tabExists(tab){return Boolean(children.filter(tab).length);}
function isFirst(){return current===0;}
function isInt(num){return num%1===0;}
function isLast(){return current===children.length-1;}
function filterTab(tab){return $(this).attr('href').match(new RegExp(tab+'$'));}
function getTab(tab){if(tab instanceof $){return{tab:tab,link:options.links.eq(tab.index())};}
if(isInt(tab)){return{tab:children.eq(tab),link:options.links.eq(tab)};}
if(children.filter(tab).length){return{tab:children.filter(tab),link:options.links.filter(function(){return filterTab.apply(this,[tab]);})};}
return{tab:children.filter('#'+tab),link:options.links.filter(function(){return filterTab.apply(this,['#'+tab]);})};}
function getCurrent(){return options.links.parent().filter('.'+options.currentClass).index();}
function next(loop){++current;if(loop===undefined)loop=options.loop;if(current<children.length){return switchTab(current,true);}else if(loop&&current>=children.length){return switchTab(0,true);}
return false;}
function prev(loop){--current;if(loop===undefined)loop=options.loop;if(current>=0){return switchTab(current,true);}else if(loop&&current<0){return switchTab(children.length-1,true);}
return false;}
function onSwitch(tab){if(options.history&&options.historyOnInit&&firstTime&&history!==undefined&&('pushState'in history)){firstTime=false;window.setTimeout(function(){history.replaceState(null,'',tab);},100);}
current=getCurrent();if(options.onSwitch&&typeof options.onSwitch==='function'){options.onSwitch(tab,api());}
tabcontent.trigger('tabcontent.switch',[tab,api()]);}
function switchTab(tab,api){if(!tab.toString().match(/^#/)){tab='#'+getTab(tab).tab.attr('id');}
if(!tabExists(tab)){return false;}
options.links.attr('aria-selected','false').parent().removeClass(options.currentClass);options.links.filter(function(){return filterTab.apply(this,[tab]);}).attr('aria-selected','true').parent().addClass(options.currentClass);children.hide();if(options.history&&api){if(history!==undefined&&('pushState'in history)){history.pushState(null,'',tab);}else{window.location.hash=tab;}}
children.attr('aria-hidden','true').filter(tab).show(options.speed,function(){if(options.speed){onSwitch(tab);}}).attr('aria-hidden','false');if(!options.speed){onSwitch(tab);}
return true;}
function apiSwitch(tab){return switchTab(tab,true);}
function hashSwitch(e){switchTab(loc.hash);}
function init(){if(tabExists(loc.hash)){switchTab(loc.hash);}
else if(options.links.parent().filter('.'+options.currentClass).length){switchTab(options.links.parent().filter('.'+options.currentClass).index());}
else if(options.errorSelector&&children.find(options.errorSelector).length){children.each(function(){if($(this).find(options.errorSelector).length){switchTab("#"+$(this).attr("id"));return false;}});}
else{switchTab("#"+children.filter(":first-child").attr("id"));}
if(options.errorSelector){children.find(options.errorSelector).each(function(){var tab=getTab($(this).parent());tab.link.parent().addClass(options.tabErrorClass);});}
if('onhashchange'in window){$(window).bind('hashchange',hashSwitch);}else{var current_href=loc.href;window.setInterval(function(){if(current_href!==loc.href){hashSwitch.call(window.event);current_href=loc.href;}},100);}
$(options.links).on('click',function(e){switchTab($(this).attr('href').replace(/^[^#]+/,''),options.history);e.preventDefault();});if(options.onInit&&typeof options.onInit==='function'){options.onInit(api());}
tabcontent.trigger('tabcontent.init',[api()]);}
function api(){return{'switch':apiSwitch,'switchTab':apiSwitch,'getCurrent':getCurrent,'getTab':getTab,'next':next,'prev':prev,'isFirst':isFirst,'isLast':isLast};}
init();return api();};$.fn.tabbedContent=function(options){return this.each(function(){var tabs=new Tabbedcontent($(this),options);$(this).data('api',tabs);});};})(window.jQuery||window.Zepto||window.$,document,window);

BIN
docs/ui_graph.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
docs/ui_number.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/ui_select1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
docs/ui_select2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/ui_tabs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/ui_text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,262 @@
#include <DNSServer.h>
#include <ESPUI.h>
const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 1, 1);
DNSServer dnsServer;
#if defined(ESP32)
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
const char *ssid = "ESPUI";
const char *password = "espui";
const char *hostname = "espui";
uint16_t status;
uint16_t button1;
uint16_t millisLabelId;
uint16_t switchOne;
void numberCall( Control* sender, int type ) {
Serial.println( sender->value );
}
void textCall(Control *sender, int type) {
Serial.print("Text: ID: ");
Serial.print(sender->id);
Serial.print(", Value: ");
Serial.println(sender->value);
}
void slider(Control *sender, int type) {
Serial.print("Slider: ID: ");
Serial.print(sender->id);
Serial.print(", Value: ");
Serial.println(sender->value);
}
void buttonCallback(Control *sender, int type) {
switch (type) {
case B_DOWN:
Serial.println("Button DOWN");
break;
case B_UP:
Serial.println("Button UP");
break;
}
}
void buttonExample(Control *sender, int type) {
switch (type) {
case B_DOWN:
Serial.println("Status: Start");
ESPUI.updateControlValue(status, "Start");
ESPUI.getControl(button1)->color = ControlColor::Carrot;
ESPUI.updateControl(button1);
break;
case B_UP:
Serial.println("Status: Stop");
ESPUI.updateControlValue(status, "Stop");
ESPUI.getControl(button1)->color = ControlColor::Peterriver;
ESPUI.updateControl(button1);
break;
}
}
void padExample(Control *sender, int value) {
switch (value) {
case P_LEFT_DOWN:
Serial.print("left down");
break;
case P_LEFT_UP:
Serial.print("left up");
break;
case P_RIGHT_DOWN:
Serial.print("right down");
break;
case P_RIGHT_UP:
Serial.print("right up");
break;
case P_FOR_DOWN:
Serial.print("for down");
break;
case P_FOR_UP:
Serial.print("for up");
break;
case P_BACK_DOWN:
Serial.print("back down");
break;
case P_BACK_UP:
Serial.print("back up");
break;
case P_CENTER_DOWN:
Serial.print("center down");
break;
case P_CENTER_UP:
Serial.print("center up");
break;
}
Serial.print(" ");
Serial.println(sender->id);
}
void switchExample(Control *sender, int value) {
switch (value) {
case S_ACTIVE:
Serial.print("Active:");
break;
case S_INACTIVE:
Serial.print("Inactive");
break;
}
Serial.print(" ");
Serial.println(sender->id);
}
void selectExample(Control *sender, int value) {
Serial.print("Select: ID: ");
Serial.print(sender->id);
Serial.print(", Value: ");
Serial.println(sender->value);
}
void otherSwitchExample(Control *sender, int value) {
switch (value) {
case S_ACTIVE:
Serial.print("Active:");
break;
case S_INACTIVE:
Serial.print("Inactive");
break;
}
Serial.print(" ");
Serial.println(sender->id);
}
void setup(void) {
ESPUI.setVerbosity(Verbosity::VerboseJSON);
Serial.begin(115200);
#if defined(ESP32)
WiFi.setHostname(hostname);
#else
WiFi.hostname(hostname);
#endif
// try to connect to existing network
WiFi.begin(ssid, password);
Serial.print("\n\nTry to connect to existing network");
{
uint8_t timeout = 10;
// Wait for connection, 5s timeout
do {
delay(500);
Serial.print(".");
timeout--;
} while (timeout && WiFi.status() != WL_CONNECTED);
// not connected -> create hotspot
if (WiFi.status() != WL_CONNECTED) {
Serial.print("\n\nCreating hotspot");
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
WiFi.softAP(ssid);
timeout = 5;
do {
delay(500);
Serial.print(".");
timeout--;
} while (timeout);
}
}
dnsServer.start(DNS_PORT, "*", apIP);
Serial.println("\n\nWiFi parameters:");
Serial.print("Mode: ");
Serial.println(WiFi.getMode() == WIFI_AP ? "Station" : "Client");
Serial.print("IP address: ");
Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP());
status = ESPUI.addControl(ControlType::Label, "Status:", "Stop", ControlColor::Turquoise);
uint16_t select1 = ESPUI.addControl(ControlType::Select, "Select:", "", ControlColor::Alizarin, Control::noParent, &selectExample);
ESPUI.addControl(ControlType::Option, "Option1", "Opt1", ControlColor::Alizarin, select1);
ESPUI.addControl(ControlType::Option, "Option2", "Opt2", ControlColor::Alizarin, select1);
ESPUI.addControl(ControlType::Option, "Option3", "Opt3", ControlColor::Alizarin, select1);
ESPUI.addControl(ControlType::Text, "Text Test:", "a Text Field", ControlColor::Alizarin, Control::noParent, &textCall);
millisLabelId = ESPUI.addControl(ControlType::Label, "Millis:", "0", ControlColor::Emerald, Control::noParent);
button1 = ESPUI.addControl(ControlType::Button, "Push Button", "Press", ControlColor::Peterriver, Control::noParent, &buttonCallback);
ESPUI.addControl(ControlType::Button, "Other Button", "Press", ControlColor::Wetasphalt, Control::noParent, &buttonExample);
ESPUI.addControl(ControlType::PadWithCenter, "Pad with center", "", ControlColor::Sunflower, Control::noParent, &padExample);
ESPUI.addControl(ControlType::Pad, "Pad without center", "", ControlColor::Carrot, Control::noParent, &padExample);
switchOne = ESPUI.addControl(ControlType::Switcher, "Switch one", "", ControlColor::Alizarin, Control::noParent, &switchExample);
ESPUI.addControl(ControlType::Switcher, "Switch two", "", ControlColor::None, Control::noParent, &otherSwitchExample);
ESPUI.addControl(ControlType::Slider, "Slider one", "30", ControlColor::Alizarin, Control::noParent, &slider);
ESPUI.addControl(ControlType::Slider, "Slider two", "100", ControlColor::Alizarin, Control::noParent, &slider);
ESPUI.addControl(ControlType::Number, "Number:", "50", ControlColor::Alizarin, Control::noParent, &numberCall);
/*
* .begin loads and serves all files from PROGMEM directly.
* If you want to serve the files from SPIFFS use ESPUI.beginSPIFFS
* (.prepareFileSystem has to be run in an empty sketch before)
*/
// Enable this option if you want sliders to be continuous (update during move) and not discrete (update on stop)
// ESPUI.sliderContinuous = true;
/*
* Optionally you can use HTTP BasicAuth. Keep in mind that this is NOT a
* SECURE way of limiting access.
* Anyone who is able to sniff traffic will be able to intercept your password
* since it is transmitted in cleartext. Just add a string as username and
* password, for example begin("ESPUI Control", "username", "password")
*/
ESPUI.begin("ESPUI Control");
}
void loop(void) {
dnsServer.processNextRequest();
static long oldTime = 0;
static bool testSwitchState = false;
if (millis() - oldTime > 5000) {
ESPUI.updateControlValue(millisLabelId, String(millis()));
testSwitchState = !testSwitchState;
ESPUI.updateControlValue(switchOne, testSwitchState ? "1" : "0");
oldTime = millis();
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,28 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Control</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC"
/>
<link rel="stylesheet" href="/css/normalize.css">
<link rel="stylesheet" href="/css/style.css">
<script src="/js/zepto.min.js"></script>
<script src="/js/slider.js"></script>
<script src="/js/controls.js"></script>
</head>
<body onload="javascript:start();">
<div>
<h4><div id="mainHeader">Control</div> <span id="conStatus" class="label">Offline</span></h4></div>
<hr />
<div class="container">
<div id="row" class="row u-full-width">
</div>
</div>
</body>
</html>

View File

@ -1,487 +0,0 @@
const UI_INITIAL_GUI = 100;
const UI_TITEL = 0;
const UI_LABEL = 1;
const UPDATE_LABEL = 6;
const UI_BUTTON = 2;
const UI_SWITCHER = 3;
const UPDATE_SWITCHER = 7;
const UI_PAD = 4;
const UI_CPAD = 5;
const UI_SLIDER = 8;
const UPDATE_SLIDER = 9;
const UI_NUMBER = 10;
const UPDATE_NUMBER = 11;
const UI_TEXT_INPUT = 12;
const UPDATE_TEXT_INPUT = 13;
const UI_GRAPH = 14;
const CLEAR_GRAPH = 15;
const ADD_GRAPH_POINT = 16;
const FOR = 0;
const BACK = 1;
const LEFT = 2;
const RIGHT = 3;
const CENTER = 4;
// Colors
const C_TURQUOISE = 0;
const C_EMERALD = 1;
const C_PETERRIVER = 2;
const C_WETASPHALT = 3;
const C_SUNFLOWER = 4;
const C_CARROT = 5;
const C_ALIZARIN = 6;
const C_NONE = 7;
const C_DARK = 8;
function colorClass(colorId) {
colorId = Number(colorId);
switch (colorId) {
case C_TURQUOISE:
return "turquoise";
case C_EMERALD:
return "emerald";
case C_PETERRIVER:
return "peterriver";
case C_WETASPHALT:
return "wetasphalt";
case C_SUNFLOWER:
return "sunflower";
case C_CARROT:
return "carrot";
case C_ALIZARIN:
return "alizarin";
case C_NONE:
return "dark";
default:
return "";
}
}
var websock;
var websockConnected = false;
function restart() {
$(document)
.add("*")
.off();
$("#row").html("");
websock.close();
start();
}
function conStatusError() {
websockConnected = false;
$("#conStatus").removeClass("color-green");
$("#conStatus").addClass("color-red");
$("#conStatus").html("Error / No Connection &#8635;");
$("#conStatus").off();
$("#conStatus").on({
click: restart
});
}
function handleVisibilityChange() {
if (!websockConnected && !document.hidden) {
restart();
}
}
function start() {
document.addEventListener("visibilitychange", handleVisibilityChange, false);
websock = new WebSocket("ws://" + window.location.hostname + "/ws");
websock.onopen = function(evt) {
console.log("websock open");
$("#conStatus").addClass("color-green");
$("#conStatus").text("Connected");
websockConnected = true;
};
websock.onclose = function(evt) {
console.log("websock close");
conStatusError();
};
websock.onerror = function(evt) {
console.log(evt);
conStatusError();
};
var handleEvent = function(evt) {
//console.log(evt);
var data = JSON.parse(evt.data);
var e = document.body;
var center = "";
switch (data.type) {
case UI_INITIAL_GUI:
data.controls.forEach(element => {
var fauxEvent = {
data: JSON.stringify(element)
};
handleEvent(fauxEvent);
});
break;
case UI_TITEL:
document.title = data.label;
$("#mainHeader").html(data.label);
break;
case UI_LABEL:
$("#row").append(
"<div class='two columns card tcenter " +
colorClass(data.color) +
"'><h5 id='" +
data.id +
"'>" +
data.label +
"</h5><hr /><span id='l" +
data.id +
"' class='label label-wrap'>" +
data.value +
"</span></div>"
);
break;
case UI_BUTTON:
$("#row").append(
"<div class='one columns card tcenter " +
colorClass(data.color) +
"'><h5>" +
data.label +
"</h5><hr/><button onmousedown='buttonclick(" +
data.id +
", true)' onmouseup='buttonclick(" +
data.id +
", false)' id='" +
data.id +
"'>" +
data.value +
"</button></div>"
);
$("#" + data.id).on({
touchstart: function(e) {
e.preventDefault();
buttonclick(data.id, true);
}
});
$("#" + data.id).on({
touchend: function(e) {
e.preventDefault();
buttonclick(data.id, false);
}
});
break;
case UI_SWITCHER:
var label = "<label id='sl" + data.id + "' class='switch checked'>";
var input =
"<div class='in'><input type='checkbox' id='s" +
data.id +
"' onClick='switcher(" +
data.id +
",null)' checked></div>";
if (data.value == "0") {
label = "<label id='sl" + data.id + "' class='switch'>";
input =
"<div class='in'><input type='checkbox' id='s" +
data.id +
"' onClick='switcher(" +
data.id +
",null)' ></div>";
}
$("#row").append(
"<div id='" +
data.id +
"' class='one columns card tcenter " +
colorClass(data.color) +
"'><h5>" +
data.label +
"</h5><hr/>" +
label +
input +
"</label>" +
"</div>"
);
break;
case UI_CPAD:
center =
"<a class='confirm' onmousedown='padclick(CENTER, " +
data.id +
", true)' onmouseup='padclick(CENTER, " +
data.id +
", false)' href='#' id='pc" +
data.id +
"'>OK</a>";
//NO BREAK
case UI_PAD:
$("#row").append(
"<div class='two columns card tcenter " +
colorClass(data.color) +
"'><h5>" +
data.label +
"</h5><hr/>" +
"<nav class='control'>" +
"<ul>" +
"<li><a onmousedown='padclick(FOR, " +
data.id +
", true)' onmouseup='padclick(FOR, " +
data.id +
", false)' href='#' id='pf" +
data.id +
"'>▲</a></li>" +
"<li><a onmousedown='padclick(RIGHT, " +
data.id +
", true)' onmouseup='padclick(RIGHT, " +
data.id +
", false)' href='#' id='pr" +
data.id +
"'>▲</a></li>" +
"<li><a onmousedown='padclick(LEFT, " +
data.id +
", true)' onmouseup='padclick(LEFT, " +
data.id +
", false)' href='#' id='pl" +
data.id +
"'>▲</a></li>" +
"<li><a onmousedown='padclick(BACK, " +
data.id +
", true)' onmouseup='padclick(BACK, " +
data.id +
", false)' href='#' id='pb" +
data.id +
"'>▲</a></li>" +
"</ul>" +
center +
"</nav>" +
"</div>"
);
$("#pf" + data.id).on({
touchstart: function(e) {
e.preventDefault();
padclick(FOR, data.id, true);
}
});
$("#pf" + data.id).on({
touchend: function(e) {
e.preventDefault();
padclick(FOR, data.id, false);
}
});
$("#pl" + data.id).on({
touchstart: function(e) {
e.preventDefault();
padclick(LEFT, data.id, true);
}
});
$("#pl" + data.id).on({
touchend: function(e) {
e.preventDefault();
padclick(LEFT, data.id, false);
}
});
$("#pr" + data.id).on({
touchstart: function(e) {
e.preventDefault();
padclick(RIGHT, data.id, true);
}
});
$("#pr" + data.id).on({
touchend: function(e) {
e.preventDefault();
padclick(RIGHT, data.id, false);
}
});
$("#pb" + data.id).on({
touchstart: function(e) {
e.preventDefault();
padclick(BACK, data.id, true);
}
});
$("#pb" + data.id).on({
touchend: function(e) {
e.preventDefault();
padclick(BACK, data.id, false);
}
});
$("#pc" + data.id).on({
touchstart: function(e) {
e.preventDefault();
padclick(CENTER, data.id, true);
}
});
$("#pc" + data.id).on({
touchend: function(e) {
e.preventDefault();
padclick(CENTER, data.id, false);
}
});
break;
case UPDATE_LABEL:
$("#l" + data.id).html(data.value);
break;
case UPDATE_SWITCHER:
if (data.value == "0") switcher(data.id, 0);
else switcher(data.id, 1);
break;
case UI_SLIDER:
$("#row").append(
"<div class='two columns card tcenter card-slider " +
colorClass(data.color) +
"'>" +
"<h5 id='" +
data.id +
"'>" +
data.label +
"</h5><hr />" +
"<div id='sl" +
data.id +
"' class='rkmd-slider slider-discrete slider-" +
colorClass(data.color) +
"'>" +
"<input type='range' min='0' max='100' value='" +
data.value +
"'>" +
"</div>" +
"</div>"
);
$("#row").append(
"<script>" + "rkmd_rangeSlider('#sl" + data.id + "');" + "</script>"
);
break;
case UPDATE_SLIDER:
slider_move($("#sl" + data.id), data.value, "100", false);
break;
case UI_NUMBER:
$("#row").append(
"<div class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5 id='" +
data.id +
"'>" +
data.label +
"</h5><hr />" +
"<input style='color:black;' id='num" +
data.id +
"' type='number' value='" +
data.value +
"' onchange='numberchange(" +
data.id +
")' />" +
"</div>"
);
break;
case UPDATE_NUMBER:
$("#num" + data.id).val(data.value);
break;
case UI_TEXT_INPUT:
$("#row").append(
"<div class='two columns card tcenter " +
colorClass(data.color) +
"'>" +
"<h5 id='" +
data.id +
"'>" +
data.label +
"</h5><hr />" +
"<input style='color:black;' id='text" +
data.id +
"' value='" +
data.value +
"' onchange='textchange(" +
data.id +
")' />" +
"</div>"
);
break;
case UPDATE_TEXT_INPUT:
$("#text" + data.id).val(data.value);
break;
default:
console.error("Unknown type or event");
break;
}
};
websock.onmessage = handleEvent;
}
function numberchange(number) {
var val = $("#num" + number).val();
websock.send("nvalue:" + val + ":" + number);
console.log(val);
}
function textchange(number) {
var val = $("#text" + number).val();
websock.send("tvalue:" + val + ":" + number);
console.log(val);
}
function buttonclick(number, isdown) {
if (isdown) websock.send("bdown:" + number);
else websock.send("bup:" + number);
}
function padclick(type, number, isdown) {
switch (type) {
case CENTER:
if (isdown) websock.send("pcdown:" + number);
else websock.send("pcup:" + number);
break;
case FOR:
if (isdown) websock.send("pfdown:" + number);
else websock.send("pfup:" + number);
break;
case BACK:
if (isdown) websock.send("pbdown:" + number);
else websock.send("pbup:" + number);
break;
case LEFT:
if (isdown) websock.send("pldown:" + number);
else websock.send("plup:" + number);
break;
case RIGHT:
if (isdown) websock.send("prdown:" + number);
else websock.send("prup:" + number);
break;
}
}
function switcher(number, state) {
if (state == null) {
if ($("#s" + number).is(":checked")) {
websock.send("sactive:" + number);
$("#sl" + number).addClass("checked");
} else {
websock.send("sinactive:" + number);
$("#sl" + number).removeClass("checked");
}
} else if (state == 1) {
$("#sl" + number).addClass("checked");
$("#sl" + number).prop("checked", true);
} else if (state == 0) {
$("#sl" + number).removeClass("checked");
$("#sl" + number).prop("checked", false);
}
}

View File

@ -1,142 +0,0 @@
const UI_INITIAL_GUI=100;const UI_TITEL=0;const UI_LABEL=1;const UPDATE_LABEL=6;const UI_BUTTON=2;const UI_SWITCHER=3;const UPDATE_SWITCHER=7;const UI_PAD=4;const UI_CPAD=5;const UI_SLIDER=8;const UPDATE_SLIDER=9;const UI_NUMBER=10;const UPDATE_NUMBER=11;const UI_TEXT_INPUT=12;const UPDATE_TEXT_INPUT=13;const UI_GRAPH=14;const CLEAR_GRAPH=15;const ADD_GRAPH_POINT=16;const FOR=0;const BACK=1;const LEFT=2;const RIGHT=3;const CENTER=4;const C_TURQUOISE=0;const C_EMERALD=1;const C_PETERRIVER=2;const C_WETASPHALT=3;const C_SUNFLOWER=4;const C_CARROT=5;const C_ALIZARIN=6;const C_NONE=7;const C_DARK=8;function colorClass(colorId){colorId=Number(colorId);switch(colorId){case C_TURQUOISE:return"turquoise";case C_EMERALD:return"emerald";case C_PETERRIVER:return"peterriver";case C_WETASPHALT:return"wetasphalt";case C_SUNFLOWER:return"sunflower";case C_CARROT:return"carrot";case C_ALIZARIN:return"alizarin";case C_NONE:return"dark";default:return"";}}
var websock;var websockConnected=false;function restart(){$(document).add("*").off();$("#row").html("");websock.close();start();}
function conStatusError(){websockConnected=false;$("#conStatus").removeClass("color-green");$("#conStatus").addClass("color-red");$("#conStatus").html("Error / No Connection &#8635;");$("#conStatus").off();$("#conStatus").on({click:restart});}
function handleVisibilityChange(){if(!websockConnected&&!document.hidden){restart();}}
function start(){document.addEventListener("visibilitychange",handleVisibilityChange,false);websock=new WebSocket("ws://"+window.location.hostname+"/ws");websock.onopen=function(evt){console.log("websock open");$("#conStatus").addClass("color-green");$("#conStatus").text("Connected");websockConnected=true;};websock.onclose=function(evt){console.log("websock close");conStatusError();};websock.onerror=function(evt){console.log(evt);conStatusError();};var handleEvent=function(evt){var data=JSON.parse(evt.data);var e=document.body;var center="";switch(data.type){case UI_INITIAL_GUI:data.controls.forEach(element=>{var fauxEvent={data:JSON.stringify(element)};handleEvent(fauxEvent);});break;case UI_TITEL:document.title=data.label;$("#mainHeader").html(data.label);break;case UI_LABEL:$("#row").append("<div class='two columns card tcenter "+
colorClass(data.color)+
"'><h5 id='"+
data.id+
"'>"+
data.label+
"</h5><hr /><span id='l"+
data.id+
"' class='label label-wrap'>"+
data.value+
"</span></div>");break;case UI_BUTTON:$("#row").append("<div class='one columns card tcenter "+
colorClass(data.color)+
"'><h5>"+
data.label+
"</h5><hr/><button onmousedown='buttonclick("+
data.id+
", true)' onmouseup='buttonclick("+
data.id+
", false)' id='"+
data.id+
"'>"+
data.value+
"</button></div>");$("#"+data.id).on({touchstart:function(e){e.preventDefault();buttonclick(data.id,true);}});$("#"+data.id).on({touchend:function(e){e.preventDefault();buttonclick(data.id,false);}});break;case UI_SWITCHER:var label="<label id='sl"+data.id+"' class='switch checked'>";var input="<div class='in'><input type='checkbox' id='s"+
data.id+
"' onClick='switcher("+
data.id+
",null)' checked></div>";if(data.value=="0"){label="<label id='sl"+data.id+"' class='switch'>";input="<div class='in'><input type='checkbox' id='s"+
data.id+
"' onClick='switcher("+
data.id+
",null)' ></div>";}
$("#row").append("<div id='"+
data.id+
"' class='one columns card tcenter "+
colorClass(data.color)+
"'><h5>"+
data.label+
"</h5><hr/>"+
label+
input+
"</label>"+
"</div>");break;case UI_CPAD:center="<a class='confirm' onmousedown='padclick(CENTER, "+
data.id+
", true)' onmouseup='padclick(CENTER, "+
data.id+
", false)' href='#' id='pc"+
data.id+
"'>OK</a>";case UI_PAD:$("#row").append("<div class='two columns card tcenter "+
colorClass(data.color)+
"'><h5>"+
data.label+
"</h5><hr/>"+
"<nav class='control'>"+
"<ul>"+
"<li><a onmousedown='padclick(FOR, "+
data.id+
", true)' onmouseup='padclick(FOR, "+
data.id+
", false)' href='#' id='pf"+
data.id+
"'>▲</a></li>"+
"<li><a onmousedown='padclick(RIGHT, "+
data.id+
", true)' onmouseup='padclick(RIGHT, "+
data.id+
", false)' href='#' id='pr"+
data.id+
"'>▲</a></li>"+
"<li><a onmousedown='padclick(LEFT, "+
data.id+
", true)' onmouseup='padclick(LEFT, "+
data.id+
", false)' href='#' id='pl"+
data.id+
"'>▲</a></li>"+
"<li><a onmousedown='padclick(BACK, "+
data.id+
", true)' onmouseup='padclick(BACK, "+
data.id+
", false)' href='#' id='pb"+
data.id+
"'>▲</a></li>"+
"</ul>"+
center+
"</nav>"+
"</div>");$("#pf"+data.id).on({touchstart:function(e){e.preventDefault();padclick(FOR,data.id,true);}});$("#pf"+data.id).on({touchend:function(e){e.preventDefault();padclick(FOR,data.id,false);}});$("#pl"+data.id).on({touchstart:function(e){e.preventDefault();padclick(LEFT,data.id,true);}});$("#pl"+data.id).on({touchend:function(e){e.preventDefault();padclick(LEFT,data.id,false);}});$("#pr"+data.id).on({touchstart:function(e){e.preventDefault();padclick(RIGHT,data.id,true);}});$("#pr"+data.id).on({touchend:function(e){e.preventDefault();padclick(RIGHT,data.id,false);}});$("#pb"+data.id).on({touchstart:function(e){e.preventDefault();padclick(BACK,data.id,true);}});$("#pb"+data.id).on({touchend:function(e){e.preventDefault();padclick(BACK,data.id,false);}});$("#pc"+data.id).on({touchstart:function(e){e.preventDefault();padclick(CENTER,data.id,true);}});$("#pc"+data.id).on({touchend:function(e){e.preventDefault();padclick(CENTER,data.id,false);}});break;case UPDATE_LABEL:$("#l"+data.id).html(data.value);break;case UPDATE_SWITCHER:if(data.value=="0")switcher(data.id,0);else switcher(data.id,1);break;case UI_SLIDER:$("#row").append("<div class='two columns card tcenter card-slider "+
colorClass(data.color)+
"'>"+
"<h5 id='"+
data.id+
"'>"+
data.label+
"</h5><hr />"+
"<div id='sl"+
data.id+
"' class='rkmd-slider slider-discrete slider-"+
colorClass(data.color)+
"'>"+
"<input type='range' min='0' max='100' value='"+
data.value+
"'>"+
"</div>"+
"</div>");$("#row").append("<script>"+"rkmd_rangeSlider('#sl"+data.id+"');"+"</script>");break;case UPDATE_SLIDER:slider_move($("#sl"+data.id),data.value,"100",false);break;case UI_NUMBER:$("#row").append("<div class='two columns card tcenter "+
colorClass(data.color)+
"'>"+
"<h5 id='"+
data.id+
"'>"+
data.label+
"</h5><hr />"+
"<input style='color:black;' id='num"+
data.id+
"' type='number' value='"+
data.value+
"' onchange='numberchange("+
data.id+
")' />"+
"</div>");break;case UPDATE_NUMBER:$("#num"+data.id).val(data.value);break;case UI_TEXT_INPUT:$("#row").append("<div class='two columns card tcenter "+
colorClass(data.color)+
"'>"+
"<h5 id='"+
data.id+
"'>"+
data.label+
"</h5><hr />"+
"<input style='color:black;' id='text"+
data.id+
"' value='"+
data.value+
"' onchange='textchange("+
data.id+
")' />"+
"</div>");break;case UPDATE_TEXT_INPUT:$("#text"+data.id).val(data.value);break;default:console.error("Unknown type or event");break;}};websock.onmessage=handleEvent;}
function numberchange(number){var val=$("#num"+number).val();websock.send("nvalue:"+val+":"+number);console.log(val);}
function textchange(number){var val=$("#text"+number).val();websock.send("tvalue:"+val+":"+number);console.log(val);}
function buttonclick(number,isdown){if(isdown)websock.send("bdown:"+number);else websock.send("bup:"+number);}
function padclick(type,number,isdown){switch(type){case CENTER:if(isdown)websock.send("pcdown:"+number);else websock.send("pcup:"+number);break;case FOR:if(isdown)websock.send("pfdown:"+number);else websock.send("pfup:"+number);break;case BACK:if(isdown)websock.send("pbdown:"+number);else websock.send("pbup:"+number);break;case LEFT:if(isdown)websock.send("pldown:"+number);else websock.send("plup:"+number);break;case RIGHT:if(isdown)websock.send("prdown:"+number);else websock.send("prup:"+number);break;}}
function switcher(number,state){if(state==null){if($("#s"+number).is(":checked")){websock.send("sactive:"+number);$("#sl"+number).addClass("checked");}else{websock.send("sinactive:"+number);$("#sl"+number).removeClass("checked");}}else if(state==1){$("#sl"+number).addClass("checked");$("#sl"+number).prop("checked",true);}else if(state==0){$("#sl"+number).removeClass("checked");$("#sl"+number).prop("checked",false);}}

View File

@ -1,125 +0,0 @@
/* -----------------------------------------------------
Material Design Sliders
CodePen URL: https://codepen.io/rkchauhan/pen/xVGGpR
By: Ravikumar Chauhan
-------------------------------------------------------- */
function rkmd_rangeSlider(selector) {
var self, slider_width, slider_offset, curnt, sliderDiscrete, range, slider;
self = $(selector);
slider_width = self.width();
slider_offset = self.offset().left;
sliderDiscrete = self;
sliderDiscrete.each(function(i, v) {
curnt = $(this);
curnt.append(sliderDiscrete_tmplt());
range = curnt.find('input[type="range"]');
slider = curnt.find('.slider');
slider_fill = slider.find('.slider-fill');
slider_handle = slider.find('.slider-handle');
slider_label = slider.find('.slider-label');
var range_val = parseInt(range.val());
slider_fill.css('width', range_val + '%');
slider_handle.css('left', range_val + '%');
slider_label.find('span').text(range_val);
});
self.on('mousedown touchstart', '.slider-handle', function(e) {
if (e.button === 2) {
return false;
}
var parents = $(this).parents('.rkmd-slider');
var slider_width = parents.width();
var slider_offset = parents.offset().left;
var check_range = parents.find('input[type="range"]').is(':disabled');
if (check_range === true) {
return false;
}
$(this).addClass('is-active');
var moveFu =
function(e) {
var pageX = e.pageX || e.changedTouches[0].pageX;
var slider_new_width = pageX - slider_offset;
if (slider_new_width <= slider_width && !(slider_new_width < '0')) {
slider_move(parents, slider_new_width, slider_width, true);
}
};
var upFu =
function(e) {
$(this).off(handlers);
parents.find('.is-active').removeClass('is-active');
};
var handlers = {
mousemove: moveFu,
touchmove: moveFu,
mouseup: upFu,
touchend: upFu
};
$(document).on(handlers);
});
self.on('mousedown touchstart', '.slider', function(e) {
if (e.button === 2) {
return false;
}
var parents = $(this).parents('.rkmd-slider');
var slider_width = parents.width();
var slider_offset = parents.offset().left;
var check_range = parents.find('input[type="range"]').is(':disabled');
if (check_range === true) {
return false;
}
var slider_new_width = e.pageX - slider_offset;
if (slider_new_width <= slider_width && !(slider_new_width < '0')) {
slider_move(parents, slider_new_width, slider_width, true);
}
var upFu =
function(e) {
$(this).off(handlers);
};
var handlers = {
mouseup: upFu,
touchend: upFu
};
$(document).on(handlers);
});
};
function sliderDiscrete_tmplt() {
var tmplt = '<div class="slider">' +
'<div class="slider-fill"></div>' +
'<div class="slider-handle"><div class="slider-label"><span>0</span></div></div>' +
'</div>';
return tmplt;
}
function slider_move(parents, newW, sliderW, send) {
var slider_new_val = parseInt(Math.round(newW / sliderW * 100));
var slider_fill = parents.find('.slider-fill');
var slider_handle = parents.find('.slider-handle');
var range = parents.find('input[type="range"]');
slider_fill.css('width', slider_new_val + '%');
slider_handle.css({
'left': slider_new_val + '%',
'transition': 'none',
'-webkit-transition': 'none',
'-moz-transition': 'none'
});
range.val(slider_new_val);
if (parents.find('.slider-handle span').text() != slider_new_val) {
parents.find('.slider-handle span').text(slider_new_val);
var number = parents.attr('id').substring(2);
if (send) websock.send('slvalue:' + slider_new_val + ':' + number);
}
}

View File

@ -1,10 +0,0 @@
function rkmd_rangeSlider(selector){var self,slider_width,slider_offset,curnt,sliderDiscrete,range,slider;self=$(selector);slider_width=self.width();slider_offset=self.offset().left;sliderDiscrete=self;sliderDiscrete.each(function(i,v){curnt=$(this);curnt.append(sliderDiscrete_tmplt());range=curnt.find('input[type="range"]');slider=curnt.find('.slider');slider_fill=slider.find('.slider-fill');slider_handle=slider.find('.slider-handle');slider_label=slider.find('.slider-label');var range_val=parseInt(range.val());slider_fill.css('width',range_val+'%');slider_handle.css('left',range_val+'%');slider_label.find('span').text(range_val);});self.on('mousedown touchstart','.slider-handle',function(e){if(e.button===2){return false;}
var parents=$(this).parents('.rkmd-slider');var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(':disabled');if(check_range===true){return false;}
$(this).addClass('is-active');var moveFu=function(e){var pageX=e.pageX||e.changedTouches[0].pageX;var slider_new_width=pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<'0')){slider_move(parents,slider_new_width,slider_width,true);}};var upFu=function(e){$(this).off(handlers);parents.find('.is-active').removeClass('is-active');};var handlers={mousemove:moveFu,touchmove:moveFu,mouseup:upFu,touchend:upFu};$(document).on(handlers);});self.on('mousedown touchstart','.slider',function(e){if(e.button===2){return false;}
var parents=$(this).parents('.rkmd-slider');var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(':disabled');if(check_range===true){return false;}
var slider_new_width=e.pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<'0')){slider_move(parents,slider_new_width,slider_width,true);}
var upFu=function(e){$(this).off(handlers);};var handlers={mouseup:upFu,touchend:upFu};$(document).on(handlers);});};function sliderDiscrete_tmplt(){var tmplt='<div class="slider">'+
'<div class="slider-fill"></div>'+
'<div class="slider-handle"><div class="slider-label"><span>0</span></div></div>'+
'</div>';return tmplt;}
function slider_move(parents,newW,sliderW,send){var slider_new_val=parseInt(Math.round(newW/sliderW*100));var slider_fill=parents.find('.slider-fill');var slider_handle=parents.find('.slider-handle');var range=parents.find('input[type="range"]');slider_fill.css('width',slider_new_val+'%');slider_handle.css({'left':slider_new_val+'%','transition':'none','-webkit-transition':'none','-moz-transition':'none'});range.val(slider_new_val);if(parents.find('.slider-handle span').text()!=slider_new_val){parents.find('.slider-handle span').text(slider_new_val);var number=parents.attr('id').substring(2);if(send)websock.send('slvalue:'+slider_new_val+':'+number);}}

View File

@ -12,174 +12,237 @@ DNSServer dnsServer;
#endif
const char *ssid = "ESPUI";
const char *password = "";
const char *password = "espui";
long oldTime = 0;
bool switchi = false;
const char *hostname = "espui";
void numberCall(Control sender, int type) { Serial.println(sender.value); }
int statusLabelId;
int graphId;
int millisLabelId;
int testSwitchId;
void textCall(Control sender, int type) { Serial.println(sender.value); }
void numberCall(Control *sender, int type) { Serial.println(sender->value); }
void slider(Control sender, int type) { Serial.println(sender.value); }
void textCall(Control *sender, int type) {
Serial.print("Text: ID: ");
Serial.print(sender->id);
Serial.print(", Value: ");
Serial.println(sender->value);
}
void buttonCallback(Control sender, int type) {
void slider(Control *sender, int type) {
Serial.print("Slider: ID: ");
Serial.print(sender->id);
Serial.print(", Value: ");
Serial.println(sender->value);
// Like all Control Values in ESPUI slider values are Strings. To use them as int simply do this:
int sliderValueWithOffset = sender->value.toInt() + 100;
Serial.print("SliderValue with offset");
Serial.println(sliderValueWithOffset);
}
void buttonCallback(Control *sender, int type) {
switch (type) {
case B_DOWN:
Serial.println("Button DOWN");
break;
case B_UP:
Serial.println("Button UP");
break;
case B_DOWN:
Serial.println("Button DOWN");
break;
case B_UP:
Serial.println("Button UP");
break;
}
}
void buttonExample(Control sender, int type) {
void buttonExample(Control *sender, int type) {
switch (type) {
case B_DOWN:
Serial.println("Status: Start");
ESPUI.print(0, "Status: Start");
break;
case B_UP:
Serial.println("Status: Stop");
ESPUI.print(0, "Status: Stop");
break;
case B_DOWN:
Serial.println("Status: Start");
ESPUI.print(statusLabelId, "Start");
break;
case B_UP:
Serial.println("Status: Stop");
ESPUI.print(statusLabelId, "Stop");
break;
}
}
void padExample(Control sender, int value) {
void padExample(Control *sender, int value) {
switch (value) {
case P_LEFT_DOWN:
Serial.print("left down");
break;
case P_LEFT_UP:
Serial.print("left up");
break;
case P_RIGHT_DOWN:
Serial.print("right down");
break;
case P_RIGHT_UP:
Serial.print("right up");
break;
case P_FOR_DOWN:
Serial.print("for down");
break;
case P_FOR_UP:
Serial.print("for up");
break;
case P_BACK_DOWN:
Serial.print("back down");
break;
case P_BACK_UP:
Serial.print("back up");
break;
case P_CENTER_DOWN:
Serial.print("center down");
break;
case P_CENTER_UP:
Serial.print("center up");
break;
case P_LEFT_DOWN:
Serial.print("left down");
break;
case P_LEFT_UP:
Serial.print("left up");
break;
case P_RIGHT_DOWN:
Serial.print("right down");
break;
case P_RIGHT_UP:
Serial.print("right up");
break;
case P_FOR_DOWN:
Serial.print("for down");
break;
case P_FOR_UP:
Serial.print("for up");
break;
case P_BACK_DOWN:
Serial.print("back down");
break;
case P_BACK_UP:
Serial.print("back up");
break;
case P_CENTER_DOWN:
Serial.print("center down");
break;
case P_CENTER_UP:
Serial.print("center up");
break;
}
Serial.print(" ");
Serial.println(sender.id);
Serial.println(sender->id);
}
void switchExample(Control sender, int value) {
void switchExample(Control *sender, int value) {
switch (value) {
case S_ACTIVE:
Serial.print("Active:");
break;
case S_INACTIVE:
Serial.print("Inactive");
break;
case S_ACTIVE:
Serial.print("Active:");
break;
case S_INACTIVE:
Serial.print("Inactive");
break;
}
Serial.print(" ");
Serial.println(sender.id);
Serial.println(sender->id);
}
void otherSwitchExample(Control sender, int value) {
void otherSwitchExample(Control *sender, int value) {
switch (value) {
case S_ACTIVE:
Serial.print("Active:");
break;
case S_INACTIVE:
Serial.print("Inactive");
break;
case S_ACTIVE:
Serial.print("Active:");
break;
case S_INACTIVE:
Serial.print("Inactive");
break;
}
Serial.print(" ");
Serial.println(sender.id);
Serial.println(sender->id);
}
void setup(void) {
ESPUI.setVerbosity(Verbosity::VerboseJSON);
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
/*
#if defined(ESP32)
WiFi.setHostname(ssid);
#else
WiFi.hostname(ssid);
#endif
*/
WiFi.softAP(ssid);
// WiFi.softAP(ssid, password);
Serial.println("");
Serial.print("IP address: ");
Serial.println(WiFi.softAPIP());
#if defined(ESP32)
WiFi.setHostname(hostname);
#else
WiFi.hostname(hostname);
#endif
// change the beginning to this if you want to join an existing network
/*
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
*/
// try to connect to existing network
WiFi.begin(ssid, password);
Serial.print("\n\nTry to connect to existing network");
ESPUI.label("Status:", COLOR_TURQUOISE, "Stop");
ESPUI.label("Millis:", COLOR_EMERALD, "0");
ESPUI.button("Push Button", &buttonCallback, COLOR_PETERRIVER);
ESPUI.button("Other Button", &buttonExample, COLOR_WETASPHALT, "Press");
ESPUI.pad("Pad with center", true, &padExample, COLOR_SUNFLOWER);
ESPUI.pad("Pad without center", false, &padExample, COLOR_CARROT);
ESPUI.switcher("Switch one", false, &switchExample, COLOR_ALIZARIN);
ESPUI.switcher("Switch two", true, &otherSwitchExample, COLOR_NONE);
ESPUI.slider("Slider one", &slider, COLOR_ALIZARIN, "30");
ESPUI.slider("Slider two", &slider, COLOR_NONE, "100");
ESPUI.text("Text Test:", &textCall, COLOR_ALIZARIN, "a Text Field");
ESPUI.number("Numbertest", &numberCall, COLOR_ALIZARIN, 5, 0, 10);
{
uint8_t timeout = 10;
/*
.begin loads and serves all files from PROGMEM directly.
If you want to serve the files from SPIFFS use ESPUI.beginSPIFFS
(.prepareFileSystem has to be run in an empty sketch before)
*/
// Wait for connection, 5s timeout
do {
delay(500);
Serial.print(".");
timeout--;
} while (timeout && WiFi.status() != WL_CONNECTED);
// not connected -> create hotspot
if (WiFi.status() != WL_CONNECTED) {
Serial.print("\n\nCreating hotspot");
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
WiFi.softAP(ssid);
timeout = 5;
do {
delay(500);
Serial.print(".");
timeout--;
} while (timeout);
}
}
dnsServer.start(DNS_PORT, "*", apIP);
Serial.println("\n\nWiFi parameters:");
Serial.print("Mode: ");
Serial.println(WiFi.getMode() == WIFI_AP ? "Station" : "Client");
Serial.print("IP address: ");
Serial.println(WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP());
statusLabelId = ESPUI.label("Status:", ControlColor::Turquoise, "Stop");
millisLabelId = ESPUI.label("Millis:", ControlColor::Emerald, "0");
ESPUI.button("Push Button", &buttonCallback, ControlColor::Peterriver, "Press");
ESPUI.button("Other Button", &buttonExample, ControlColor::Wetasphalt, "Press");
ESPUI.padWithCenter("Pad with center", &padExample, ControlColor::Sunflower);
ESPUI.pad("Pad without center", &padExample, ControlColor::Carrot);
testSwitchId = ESPUI.switcher("Switch one", &switchExample, ControlColor::Alizarin, false);
ESPUI.switcher("Switch two", &otherSwitchExample, ControlColor::None, true);
ESPUI.slider("Slider one", &slider, ControlColor::Alizarin, 30);
ESPUI.slider("Slider two", &slider, ControlColor::None, 100);
ESPUI.text("Text Test:", &textCall, ControlColor::Alizarin, "a Text Field");
ESPUI.number("Numbertest", &numberCall, ControlColor::Alizarin, 5, 0, 10);
graphId = ESPUI.graph("Graph Test", ControlColor::Wetasphalt);
/*
* .begin loads and serves all files from PROGMEM directly.
* If you want to serve the files from SPIFFS use ESPUI.beginSPIFFS
* (.prepareFileSystem has to be run in an empty sketch before)
*/
// Enable this option if you want sliders to be continuous (update during move) and not discrete (update on stop)
// ESPUI.sliderContinuous = true;
/*
* Optionally you can use HTTP BasicAuth. Keep in mind that this is NOT a
SECURE way of limiting access.
* SECURE way of limiting access.
* Anyone who is able to sniff traffic will be able to intercept your password
since it is transmitted in cleartext ESPUI.begin("ESPUI Control", "myuser",
"mypassword");
*/
* since it is transmitted in cleartext. Just add a string as username and
* password, for example begin("ESPUI Control", "username", "password")
*/
ESPUI.begin("ESPUI Control");
}
void loop(void) {
dnsServer.processNextRequest();
static long oldTime = 0;
static bool testSwitchState = false;
if (millis() - oldTime > 5000) {
ESPUI.print("Millis:", String(millis()));
switchi = !switchi;
ESPUI.updateSwitcher("Switch one", switchi);
ESPUI.print(millisLabelId, String(millis()));
ESPUI.addGraphPoint(graphId, random(1, 50));
testSwitchState = !testSwitchState;
ESPUI.updateSwitcher(testSwitchId, testSwitchState);
oldTime = millis();
}
}

View File

@ -1,9 +1,11 @@
#include <ESPUI.h>
void setup(void) {
void setup(void)
{
Serial.begin(115200);
ESPUI.prepareFileSystem();
}
void loop() {
void loop()
{
}

View File

@ -0,0 +1,262 @@
#include <DNSServer.h>
#include <ESPUI.h>
const byte DNS_PORT = 53;
IPAddress apIP( 192, 168, 1, 1 );
DNSServer dnsServer;
#if defined(ESP32)
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
const char* ssid = "ESPUI";
const char* password = "espui";
const char* hostname = "espui";
uint16_t button1;
uint16_t switchOne;
uint16_t status;
void numberCall( Control* sender, int type ) {
Serial.println( sender->value );
}
void textCall( Control* sender, int type ) {
Serial.print("Text: ID: ");
Serial.print(sender->id);
Serial.print(", Value: ");
Serial.println( sender->value );}
void slider( Control* sender, int type ) {
Serial.print("Slider: ID: ");
Serial.print(sender->id);
Serial.print(", Value: ");
Serial.println( sender->value );}
void buttonCallback( Control* sender, int type ) {
switch ( type ) {
case B_DOWN:
Serial.println( "Button DOWN" );
break;
case B_UP:
Serial.println( "Button UP" );
break;
}
}
void buttonExample( Control* sender, int type ) {
switch ( type ) {
case B_DOWN:
Serial.println( "Status: Start" );
ESPUI.updateControlValue( status, "Start" );
ESPUI.getControl( button1 )->color = ControlColor::Carrot;
ESPUI.updateControl( button1 );
break;
case B_UP:
Serial.println( "Status: Stop" );
ESPUI.updateControlValue( status, "Stop" );
ESPUI.getControl( button1 )->color = ControlColor::Peterriver;
ESPUI.updateControl( button1 );
break;
}
}
void padExample( Control* sender, int value ) {
switch ( value ) {
case P_LEFT_DOWN:
Serial.print( "left down" );
break;
case P_LEFT_UP:
Serial.print( "left up" );
break;
case P_RIGHT_DOWN:
Serial.print( "right down" );
break;
case P_RIGHT_UP:
Serial.print( "right up" );
break;
case P_FOR_DOWN:
Serial.print( "for down" );
break;
case P_FOR_UP:
Serial.print( "for up" );
break;
case P_BACK_DOWN:
Serial.print( "back down" );
break;
case P_BACK_UP:
Serial.print( "back up" );
break;
case P_CENTER_DOWN:
Serial.print( "center down" );
break;
case P_CENTER_UP:
Serial.print( "center up" );
break;
}
Serial.print( " " );
Serial.println( sender->id );
}
void switchExample( Control* sender, int value ) {
switch ( value ) {
case S_ACTIVE:
Serial.print( "Active:" );
break;
case S_INACTIVE:
Serial.print( "Inactive" );
break;
}
Serial.print( " " );
Serial.println( sender->id );
}
void selectExample( Control* sender, int value ) {
Serial.print("Select: ID: ");
Serial.print(sender->id);
Serial.print(", Value: ");
Serial.println( sender->value );
}
void otherSwitchExample( Control* sender, int value ) {
switch ( value ) {
case S_ACTIVE:
Serial.print( "Active:" );
break;
case S_INACTIVE:
Serial.print( "Inactive" );
break;
}
Serial.print( " " );
Serial.println( sender->id );
}
void setup( void ) {
Serial.begin( 115200 );
#if defined(ESP32)
WiFi.setHostname( hostname );
#else
WiFi.hostname( hostname );
#endif
// try to connect to existing network
WiFi.begin( ssid, password );
Serial.print( "\n\nTry to connect to existing network" );
{
uint8_t timeout = 10;
// Wait for connection, 5s timeout
do {
delay( 500 );
Serial.print( "." );
timeout--;
} while ( timeout && WiFi.status() != WL_CONNECTED );
// not connected -> create hotspot
if ( WiFi.status() != WL_CONNECTED ) {
Serial.print( "\n\nCreating hotspot" );
WiFi.mode( WIFI_AP );
WiFi.softAPConfig( apIP, apIP, IPAddress( 255, 255, 255, 0 ) );
WiFi.softAP( ssid );
timeout = 5;
do {
delay( 500 );
Serial.print( "." );
timeout--;
} while ( timeout );
}
}
dnsServer.start( DNS_PORT, "*", apIP );
Serial.println( "\n\nWiFi parameters:" );
Serial.print( "Mode: " );
Serial.println( WiFi.getMode() == WIFI_AP ? "Station" : "Client" );
Serial.print( "IP address: " );
Serial.println( WiFi.getMode() == WIFI_AP ? WiFi.softAPIP() : WiFi.localIP() );
uint16_t tab1 = ESPUI.addControl( ControlType::Tab, "Settings 1", "Settings 1" );
uint16_t tab2 = ESPUI.addControl( ControlType::Tab, "Settings 2", "Settings 2" );
uint16_t tab3 = ESPUI.addControl( ControlType::Tab, "Settings 3", "Settings 3" );
// shown above all tabs
status = ESPUI.addControl( ControlType::Label, "Status:", "Stop", ControlColor::Turquoise );
uint16_t select1 = ESPUI.addControl( ControlType::Select, "Select:", "", ControlColor::Alizarin, tab1, &selectExample );
ESPUI.addControl( ControlType::Option, "Option1", "Opt1", ControlColor::Alizarin, select1 );
ESPUI.addControl( ControlType::Option, "Option2", "Opt2", ControlColor::Alizarin, select1 );
ESPUI.addControl( ControlType::Option, "Option3", "Opt3", ControlColor::Alizarin, select1 );
ESPUI.addControl( ControlType::Text, "Text Test:", "a Text Field", ControlColor::Alizarin, tab1, &textCall );
// tabbed controls
ESPUI.addControl( ControlType::Label, "Millis:", "0", ControlColor::Emerald, tab1 );
button1 = ESPUI.addControl( ControlType::Button, "Push Button", "Press", ControlColor::Peterriver, tab1, &buttonCallback );
ESPUI.addControl( ControlType::Button, "Other Button", "Press", ControlColor::Wetasphalt, tab1, &buttonExample );
ESPUI.addControl( ControlType::PadWithCenter, "Pad with center", "", ControlColor::Sunflower, tab2, &padExample );
ESPUI.addControl( ControlType::Pad, "Pad without center", "", ControlColor::Carrot, tab3, &padExample );
switchOne = ESPUI.addControl( ControlType::Switcher, "Switch one", "", ControlColor::Alizarin, tab3, &switchExample );
ESPUI.addControl( ControlType::Switcher, "Switch two", "", ControlColor::None, tab3, &otherSwitchExample );
ESPUI.addControl( ControlType::Slider, "Slider one", "30", ControlColor::Alizarin, tab1, &slider );
ESPUI.addControl( ControlType::Slider, "Slider two", "100", ControlColor::Alizarin, tab3, &slider );
ESPUI.addControl( ControlType::Number, "Number:", "50", ControlColor::Alizarin, tab3, &numberCall );
/*
* .begin loads and serves all files from PROGMEM directly.
* If you want to serve the files from SPIFFS use ESPUI.beginSPIFFS
* (.prepareFileSystem has to be run in an empty sketch before)
*/
// Enable this option if you want sliders to be continuous (update during move) and not discrete (update on stop)
// ESPUI.sliderContinuous = true;
/*
* Optionally you can use HTTP BasicAuth. Keep in mind that this is NOT a
* SECURE way of limiting access.
* Anyone who is able to sniff traffic will be able to intercept your password
* since it is transmitted in cleartext. Just add a string as username and
* password, for example begin("ESPUI Control", "username", "password")
*/
ESPUI.begin("ESPUI Control");
}
void loop( void ) {
dnsServer.processNextRequest();
static long oldTime = 0;
static bool switchi = false;
if ( millis() - oldTime > 5000 ) {
switchi = !switchi;
ESPUI.updateControlValue( switchOne, switchi ? "1" : "0" );
oldTime = millis();
}
}

View File

@ -1,10 +1,7 @@
{
"langs":
{
"en-GB":
{
"keys":
{
"langs": {
"en-GB": {
"keys": {
"LANG_SUBCATERGORY_ESPUI": "User Interface",
"LANG_ESPUI_ESPUI_TITLE": "Title",
"LANG_ESPUI_ESPUI_HOTSPOT": "Enable Wifi Hotspot Code",
@ -22,6 +19,26 @@
"LANG_ESPUI_PAD_PAD": "UI Pad",
"LANG_ESPUI_PAD_CENTER": "Center button?"
}
},
"zh-CN": {
"keys": {
"LANG_SUBCATERGORY_ESPUI": "用户接口",
"LANG_ESPUI_ESPUI_TITLE": "标题",
"LANG_ESPUI_ESPUI_HOTSPOT": "启用无线热点代码",
"LANG_ESPUI_ESPUI_TOOLTIP": "在ESP32/ESP8266创建一网络接口",
"LANG_ESPUI_BUTTON_BUTTON": "UI 按钮",
"LANG_ESPUI_NAME": "名称",
"LANG_ESPUI_COLOR": "颜色",
"LANG_ESPUI_TEXT": "文本",
"LANG_ESPUI_BUTTON_TOOLTIP": "一个网页接口的按钮",
"LANG_ESPUI_LABEL_LABEL": "UI 标签",
"LANG_ESPUI_LABEL": "标签",
"LANG_ESPUI_LABEL_TOOLTIP": "一个网页接口的标签,你可通过修改代码去更新它",
"LANG_ESPUI_STATE": "状态",
"LANG_ESPUI_SWITCH_SWITCH": "UI 开关",
"LANG_ESPUI_PAD_PAD": "UI 面板",
"LANG_ESPUI_PAD_CENTER": "中间按钮?"
}
}
}
}
}

View File

@ -6,28 +6,24 @@
"type": "git",
"url": "https://github.com/s00500/ESPUI.git"
},
"authors": [
{
"name": "Lukas Bachschwell",
"email": "lukas@lbsfilm.at",
"url": "https://lbsfilm.at",
"maintainer": true
}
],
"dependencies": [
{
"authors": [{
"name": "Lukas Bachschwell",
"email": "lukas@lbsfilm.at",
"url": "https://lbsfilm.at",
"maintainer": true
}],
"dependencies": [{
"name": "ESP Async WebServer",
"authors": "Hristo Gochkov",
"frameworks": "arduino"
},
{
"name": "ArduinoJson",
"version": "5.13.4",
"authors": "Benoit Blanchon",
"frameworks": "arduino"
}
],
"version": "1.6.3",
"version": "2.0.2",
"frameworks": "arduino",
"platforms": "*"
}

View File

@ -1,5 +1,5 @@
name=ESPUI
version=1.6.3
version=2.0.2
author=Lukas Bachschwell
maintainer=Lukas Bachschwell <lukas@lbsfilm.at>
sentence=ESP32 and ESP8266 Web Interface Library
@ -7,3 +7,4 @@ paragraph=A simple library that implements a web graphical user interface for ES
category=Communication
url=https://github.com/s00500/ESPUI
architectures=*
depends=ArduinoJson

File diff suppressed because it is too large Load Diff

View File

@ -6,13 +6,12 @@
#include "Arduino.h"
#include "ArduinoJson.h"
#include "FS.h"
#include "stdlib_noniso.h"
#if defined(ESP32)
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include "WiFi.h"
@ -23,50 +22,150 @@
#include <ESP8266mDNS.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <Hash.h>
#include <LittleFS.h>
#include <SPIFFSEditor.h>
#define FILE_WRITE "w"
#endif
typedef struct Control {
unsigned int type;
unsigned int id; // just mirroring the id here for practical reasons
const char *label;
void (*callback)(Control, int);
String value;
unsigned int color;
} Control;
// Message Types (and control types)
#define UI_INITIAL_GUI 100
#define UI_TITEL 0
#define UI_LABEL 1
#define UPDATE_LABEL 6
enum ControlType : uint8_t
{
// fixed controls
Title = 0,
#define UI_BUTTON 2
// updatable controls
Pad,
PadWithCenter,
Button,
Label,
Switcher,
Slider,
Number,
Text,
Graph,
GraphPoint,
Tab,
Select,
Option,
Min,
Max,
Step,
Gauge,
Accel,
#define UI_SWITCHER 3
#define UPDATE_SWITCHER 7
UpdateOffset = 100,
UpdatePad = 101,
UpdatePadWithCenter,
ButtonButton,
UpdateLabel,
UpdateSwitcher,
UpdateSlider,
UpdateNumber,
UpdateText,
ClearGraph,
UpdateTab,
UpdateSelection,
UpdateOption,
UpdateMin,
UpdateMax,
UpdateStep,
UpdateGauge,
UpdateAccel,
#define UI_PAD 4
#define UI_CPAD 5
InitialGui = 200,
Reload = 201
};
#define UI_SLIDER 8
#define UPDATE_SLIDER 9
#define UI_INITIAL_GUI ControlType::InitialGui
#define UI_RELOAD ControlType::Reload
#define UI_NUMBER 10
#define UPDATE_NUMBER 11
#define UI_TITLE ControlType::Title
#define UI_LABEL ControlType::Label
#define UI_BUTTON ControlType::Button
#define UI_SWITCHER ControlType::Switcher
#define UI_PAD ControlType::Pad
#define UI_CPAD ControlType::Cpad
#define UI_SLIDER ControlType::Slider
#define UI_NUMBER ControlType::Number
#define UI_TEXT_INPUT ControlType::Text
#define UI_GRAPH ControlType::Graph
#define UI_ADD_GRAPH_POINT ControlType::GraphPoint
#define UI_TEXT_INPUT 12
#define UPDATE_TEXT_INPUT 13
#define UPDATE_LABEL ControlType::UpdateLabel
#define UPDATE_SWITCHER ControlType::UpdateSwitcher
#define UPDATE_SLIDER ControlType::UpdateSlider
#define UPDATE_NUMBER ControlType::UpdateNumber
#define UPDATE_TEXT_INPUT ControlType::UpdateText
#define CLEAR_GRAPH ControlType::ClearGraph
#define UI_GRAPH 14
#define CLEAR_GRAPH 15
#define ADD_GRAPH_POINT 16
// Colors
enum ControlColor : uint8_t
{
Turquoise,
Emerald,
Peterriver,
Wetasphalt,
Sunflower,
Carrot,
Alizarin,
Dark,
None = 0xFF
};
#define COLOR_TURQUOISE ControlColor::Turquoise
#define COLOR_EMERALD ControlColor::Emerald
#define COLOR_PETERRIVER ControlColor::Peterriver
#define COLOR_WETASPHALT ControlColor::Wetasphalt
#define COLOR_SUNFLOWER ControlColor::Sunflower
#define COLOR_CARROT ControlColor::Carrot
#define COLOR_ALIZARIN ControlColor::Alizarin
#define COLOR_DARK ControlColor::Dark
#define COLOR_NONE ControlColor::None
class Control
{
public:
ControlType type;
uint16_t id; // just mirroring the id here for practical reasons
const char* label;
void (*callback)(Control*, int);
String value;
ControlColor color;
uint16_t parentControl;
Control* next;
static constexpr uint16_t noParent = 0xffff;
Control(ControlType type, const char* label, void (*callback)(Control*, int), const String& value,
ControlColor color, uint16_t parentControl = Control::noParent)
: type(type),
label(label),
callback(callback),
value(value),
color(color),
parentControl(parentControl),
next(nullptr)
{
id = idCounter++;
}
Control(const Control& control)
: type(control.type),
id(control.id),
label(control.label),
callback(control.callback),
value(control.value),
color(control.color),
parentControl(control.parentControl),
next(control.next)
{ }
private:
static uint16_t idCounter;
};
// Values
#define B_DOWN -1
@ -89,87 +188,109 @@ typedef struct Control {
#define SL_VALUE 8
#define N_VALUE 9
#define T_VALUE 10
#define S_VALUE 11
// Colors
#define COLOR_TURQUOISE 0
#define COLOR_EMERALD 1
#define COLOR_PETERRIVER 2
#define COLOR_WETASPHALT 3
#define COLOR_SUNFLOWER 4
#define COLOR_CARROT 5
#define COLOR_ALIZARIN 6
#define COLOR_NONE 7
enum Verbosity : uint8_t
{
Quiet = 0,
Verbose,
VerboseJSON
};
class ESPUIClass {
public:
void begin(const char *_title); // Setup servers and page in Memorymode
void begin(const char *_title, const char *username, const char *password);
class ESPUIClass
{
public:
ESPUIClass()
{
verbosity = Verbosity::Quiet;
jsonUpdateDocumentSize = 2000;
jsonInitialDocumentSize = 8000;
sliderContinuous = false;
}
unsigned int jsonUpdateDocumentSize;
unsigned int jsonInitialDocumentSize;
bool sliderContinuous;
void beginSPIFFS(const char *_title); // Setup servers and page in SPIFFSmode
void beginSPIFFS(const char *_title, const char *username,
const char *password);
void setVerbosity(Verbosity verbosity);
void begin(const char* _title, const char* username = nullptr,
const char* password = nullptr); // Setup server and page in Memorymode
void beginSPIFFS(const char* _title, const char* username = nullptr,
const char* password = nullptr); // Setup server and page in SPIFFSmode
void prepareFileSystem(); // Initially preps the filesystem and loads a lot
// of stuff into SPIFFS
void list();
// Creating Elements
void prepareFileSystem(); // Initially preps the filesystem and loads a lot of
// stuff into SPIFFS
void list(); // Lists SPIFFS directory
int button(const char *label, void (*callBack)(Control, int), int color,
String value = ""); // Create Event Button
int switcher(const char *label, bool startState,
void (*callBack)(Control, int),
int color); // Create Toggle Button
int pad(const char *label, bool centerButton, void (*callBack)(Control, int),
int color); // Create Pad Control
int slider(const char *label, void (*callBack)(Control, int), int color,
String value); // Create Slider Control
int number(const char *label, void (*callBack)(Control, int), int color,
int number, int min, int max); // Create a Number Input Control
int text(const char *label, void (*callBack)(Control, int), int color,
String value = ""); // Create a Text Input Control
uint16_t addControl(ControlType type, const char* label, const String& value = String(""),
ControlColor color = ControlColor::Turquoise, uint16_t parentControl = Control::noParent,
void (*callback)(Control*, int) = nullptr);
bool removeControl(uint16_t id, bool force_reload_ui = false);
// Output only
int label(const char *label, int color, String value = ""); // Create Label
int graph(const char *label, int color); // Create Graph display
// create Elements
uint16_t button(const char* label, void (*callback)(Control*, int), ControlColor color,
const String& value = ""); // Create Event Button
uint16_t switcher(const char* label, void (*callback)(Control*, int), ControlColor color,
bool startState = false); // Create Toggle Button
uint16_t pad(const char* label, void (*callback)(Control*, int),
ControlColor color); // Create Pad Control
uint16_t padWithCenter(const char* label, void (*callback)(Control*, int),
ControlColor color); // Create Pad Control with Centerbutton
// Update Elements
void print(int id, String value);
void print(String label, String value);
uint16_t slider(const char* label, void (*callback)(Control*, int), ControlColor color, int value, int min = 0,
int max = 100); // Create Slider Control
uint16_t number(const char* label, void (*callback)(Control*, int), ControlColor color, int value, int min = 0,
int max = 100); // Create a Number Input Control
uint16_t text(const char* label, void (*callback)(Control*, int), ControlColor color,
const String& value = ""); // Create a Text Input Control
void updateSwitcher(int id, bool nValue, int clientId = -1);
void updateSwitcher(String label, bool nValue, int clientId = -1);
// Output only
uint16_t label(const char* label, ControlColor color,
const String& value = ""); // Create Label
uint16_t graph(const char* label, ControlColor color); // Create Graph display
uint16_t gauge(const char* label, ControlColor color, int value, int min = 0,
int max = 100); // Create Gauge display
void updateSlider(int id, int nValue, int clientId = -1);
void updateSlider(String label, int nValue, int clientId = -1);
// Input only
uint16_t accelerometer(const char* label, void (*callback)(Control*, int), ControlColor color);
void updateNumber(int id, int nValue, int clientId = -1);
void updateNumber(String label, int nValue, int clientId = -1);
// Update Elements
void updateText(int id, String nValue, int clientId = -1);
void updateText(String label, String nValue, int clientId = -1);
Control* getControl(uint16_t id);
void clearGraph(int id, int clientId = -1);
void clearGraph(String label, int clientId = -1);
// Update Elements
void updateControlValue(uint16_t id, const String& value, int clientId = -1);
void updateControlValue(Control* control, const String& value, int clientId = -1);
void addGraphPoint(int id, int nValue, int clientId = -1);
void addGraphPoint(String label, int nValue, int clientId = -1);
void updateControl(uint16_t id, int clientId = -1);
void updateControl(Control* control, int clientId = -1);
void textThem(String text, int clientId);
void print(uint16_t id, const String& value);
void updateLabel(uint16_t id, const String& value);
void updateSwitcher(uint16_t id, bool nValue, int clientId = -1);
void updateSlider(uint16_t id, int nValue, int clientId = -1);
void updateNumber(uint16_t id, int nValue, int clientId = -1);
void updateText(uint16_t id, const String& nValue, int clientId = -1);
void updateSelect(uint16_t id, const String& nValue, int clientId = -1);
void updateGauge(uint16_t id, int number, int clientId);
// Variables ---
const char *ui_title = "ESPUI"; // Store UI Title and Header Name
int cIndex = 0; // Control index
Control *controls[25];
void jsonDom(AsyncWebSocketClient *client);
int getIdByLabel(String label);
bool labelExists(String label);
void clearGraph(uint16_t id, int clientId = -1);
void addGraphPoint(uint16_t id, int nValue, int clientId = -1);
private:
const char *basicAuthUsername;
const char *basicAuthPassword;
bool basicAuth = true;
AsyncWebServer *server;
AsyncWebSocket *ws;
// Variables
const char* ui_title = "ESPUI"; // Store UI Title and Header Name
Control* controls = nullptr;
void jsonReload();
void jsonDom(AsyncWebSocketClient* client = nullptr);
Verbosity verbosity;
AsyncWebServer* server;
AsyncWebSocket* ws;
private:
const char* basicAuthUsername = nullptr;
const char* basicAuthPassword = nullptr;
bool basicAuth = true;
};
extern ESPUIClass ESPUI;

File diff suppressed because one or more lines are too long

19
src/dataGraphJS.h Normal file
View File

@ -0,0 +1,19 @@
const char JS_GRAPH[] PROGMEM = R"=====(
function lineGraph(parent,xAccessor,yAccessor){const width=620;const height=420;const gutter=40;const pixelsPerTick=30;function numericTransformer(dataMin,dataMax,pxMin,pxMax){var dataDiff=dataMax-dataMin,pxDiff=pxMax-pxMin,dataRatio=pxDiff/dataDiff,coordRatio=dataDiff/pxDiff;return{toCoord:function(data){return(data-dataMin)*dataRatio+pxMin;},toData:function(coord){return(coord-pxMin)*coordRatio+dataMin;}};}
function axisRenderer(orientation,transform){var axisGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var axisPath=document.createElementNS("http://www.w3.org/2000/svg","path");axisGroup.setAttribute("class",orientation+"-axis");var xMin=gutter;var xMax=width-gutter;var yMin=height-gutter;var yMax=gutter;if(orientation==="x"){axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMax+" "+yMin);for(var i=xMin;i<=xMax;i++){if((i-xMin)%pixelsPerTick===0&&i!==xMin){var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",i);text.setAttribute("y",yMin);text.setAttribute("dy","1em");axisGroup.appendChild(text);}}}else{axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMin+" "+yMax);for(var i=yMax;i<=yMin;i++){if((i-yMin)%pixelsPerTick===0&&i!==yMin){var tickGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var gridLine=document.createElementNS("http://www.w3.org/2000/svg","path");text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",xMin);text.setAttribute("y",i);text.setAttribute("dx","-.5em");text.setAttribute("dy",".3em");gridLine.setAttribute("d","M "+xMin+" "+i+" L "+xMax+" "+i);tickGroup.appendChild(gridLine);tickGroup.appendChild(text);axisGroup.appendChild(tickGroup);}}}
axisGroup.appendChild(axisPath);parent.appendChild(axisGroup);}
function lineRenderer(xAccessor,yAccessor,xTransform,yTransform){var line=document.createElementNS("http://www.w3.org/2000/svg","path");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
var pathString="M "+xTransform(xAccessor.next())+" "+yTransform(yAccessor.next());while(xAccessor.hasNext()&&yAccessor.hasNext()){pathString+=" L "+
xTransform(xAccessor.next())+
" "+
yTransform(yAccessor.next());}
line.setAttribute("class","series");line.setAttribute("d",pathString);parent.appendChild(line);}
function pointRenderer(xAccessor,yAccessor,xTransform,yTransform){var pointGroup=document.createElementNS("http://www.w3.org/2000/svg","g");pointGroup.setAttribute("class","data-points");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
while(xAccessor.hasNext()&&yAccessor.hasNext()){var xDataValue=xAccessor.next();var x=xTransform(xDataValue);var yDataValue=yAccessor.next();var y=yTransform(yDataValue);var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");circle.setAttribute("cx",x);circle.setAttribute("cy",y);circle.setAttribute("r","4");var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(xDataValue)+" / "+Math.floor(yDataValue);text.setAttribute("x",x);text.setAttribute("y",y);text.setAttribute("dx","1em");text.setAttribute("dy","-.7em");pointGroup.appendChild(circle);pointGroup.appendChild(text);}
parent.appendChild(pointGroup);}
xTransform=numericTransformer(xAccessor.min(),xAccessor.max(),0+gutter,width-gutter);yTransform=numericTransformer(yAccessor.min(),yAccessor.max(),height-gutter,0+gutter);axisRenderer("x",xTransform.toData);axisRenderer("y",yTransform.toData);lineRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);pointRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);}
function renderGraphSvg(dataArray,renderId){var figure=document.getElementById(renderId);while(figure.hasChildNodes()){figure.removeChild(figure.lastChild);}
var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 640 440");svg.setAttribute("preserveAspectRatio","xMidYMid meet");lineGraph(svg,(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].x;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.x;})),Math.max.apply(Math,dataArray.map(function(o){return o.x;}))),(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].y;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.y;})),Math.max.apply(Math,dataArray.map(function(o){return o.y;}))));figure.appendChild(svg);}
)=====";
const uint8_t JS_GRAPH_GZIP[1245] PROGMEM = { 31,139,8,0,19,56,231,94,2,255,205,87,95,111,219,54,16,127,247,167,112,4,44,16,107,89,86,27,175,3,170,240,33,109,135,174,64,18,20,77,48,96,24,246,192,73,180,76,76,150,4,138,182,69,184,254,238,59,146,162,36,219,82,134,58,45,186,135,56,226,253,231,241,119,119,228,98,157,69,130,229,217,56,101,25,253,192,73,177,116,11,194,105,38,188,234,38,138,104,89,230,220,147,246,11,237,162,60,43,197,120,203,98,177,196,175,95,5,161,89,47,41,75,150,2,207,27,66,178,22,130,114,60,183,235,130,85,52,45,63,81,254,200,162,127,240,85,16,46,172,219,108,189,162,156,69,143,156,100,229,34,231,176,112,99,34,200,29,203,60,253,159,84,94,81,169,21,252,146,10,237,54,132,143,21,227,61,91,44,112,45,49,181,26,69,165,201,90,116,106,212,20,235,51,1,87,216,48,103,86,217,139,242,156,199,134,101,105,51,35,19,114,42,214,60,219,137,252,157,146,121,99,131,213,145,161,157,225,234,133,245,140,94,52,126,38,218,111,184,247,68,254,30,104,173,178,246,215,104,235,149,137,17,189,104,67,153,212,6,195,253,62,220,143,154,44,145,138,149,159,105,22,83,14,249,201,57,131,243,81,210,153,39,108,222,76,102,148,220,7,158,175,11,28,231,17,100,54,19,126,196,41,17,244,215,148,170,213,253,131,235,44,133,40,222,204,102,219,237,214,223,94,249,57,79,102,175,130,32,152,149,155,196,241,156,196,65,161,53,244,137,192,33,159,105,167,0,93,48,213,196,227,151,84,220,8,193,217,223,107,65,93,39,74,73,89,58,94,103,39,19,103,170,132,107,247,42,45,216,128,168,94,147,10,107,212,77,59,84,169,164,12,246,14,201,32,92,175,217,162,155,46,140,177,83,57,104,103,119,119,20,85,12,129,223,141,157,137,242,62,113,224,67,154,143,91,77,35,85,67,67,33,164,220,85,190,24,214,167,205,174,177,18,8,217,100,130,118,224,211,101,83,125,178,63,29,2,31,227,224,242,146,93,96,173,100,78,76,208,74,156,155,100,165,11,9,83,255,124,150,101,148,255,246,120,119,139,239,212,198,22,41,64,202,109,208,225,50,84,203,29,238,184,114,60,214,203,144,142,103,54,218,195,139,129,233,188,164,171,131,243,37,69,1,248,124,183,100,105,236,42,29,4,8,222,195,214,233,121,201,110,104,80,243,157,100,75,157,228,107,44,117,210,219,100,203,167,146,45,219,100,3,253,155,148,71,194,89,124,11,13,243,153,229,241,195,15,191,26,58,99,57,4,140,24,180,156,169,255,179,62,254,33,112,248,87,154,109,179,244,95,39,207,142,107,76,185,182,71,117,128,44,107,113,136,111,144,55,128,74,171,161,161,57,234,23,178,96,69,161,153,130,39,76,107,161,237,205,106,112,54,189,185,103,104,122,85,51,220,60,249,120,216,175,211,231,99,168,241,232,115,10,121,118,81,40,79,40,80,36,23,173,220,146,148,247,144,39,23,125,249,114,33,79,169,118,68,193,30,85,136,202,205,3,156,93,150,96,115,106,205,22,218,205,250,153,209,52,53,219,10,200,99,129,112,11,137,164,110,79,44,151,151,189,161,180,222,39,216,128,100,244,100,0,35,21,193,232,201,16,246,163,244,20,147,245,64,114,74,184,140,80,53,133,210,94,220,182,225,244,2,36,213,208,236,96,163,200,89,38,206,5,135,86,126,118,187,106,173,12,108,89,223,99,180,84,249,157,225,244,181,135,175,39,191,186,68,253,78,210,53,197,199,167,109,110,6,184,139,135,70,216,48,101,171,44,251,148,37,238,34,229,72,57,98,60,74,207,174,78,163,13,9,53,31,199,185,87,189,119,136,167,102,239,0,143,131,229,121,61,131,190,235,240,232,100,18,138,122,6,69,213,97,118,51,53,48,87,6,47,21,195,67,229,229,147,35,101,234,255,162,249,29,56,119,43,207,100,107,144,93,223,72,70,61,53,219,106,40,129,22,76,184,231,101,210,34,112,197,50,23,121,157,53,169,96,29,76,204,181,211,235,94,85,161,130,158,52,42,143,140,202,35,163,7,23,220,198,133,153,114,77,107,209,73,111,172,250,230,237,113,44,163,242,127,42,243,21,243,203,175,95,68,135,102,52,169,78,253,183,48,212,233,159,92,155,211,207,210,135,77,162,159,92,55,156,19,233,25,198,199,216,52,137,5,75,214,188,83,170,9,21,117,37,188,149,31,99,183,17,174,199,143,17,87,157,70,67,224,62,143,105,169,250,77,77,231,116,149,111,168,65,71,77,130,86,41,52,1,213,83,17,202,232,220,218,83,191,40,132,223,35,152,111,24,221,190,205,85,37,4,227,96,252,122,30,140,231,243,160,87,178,80,141,152,111,232,77,89,208,72,232,119,35,104,193,117,42,254,3,254,198,43,74,69,61,193,204,131,30,44,120,238,193,35,214,3,168,121,43,251,158,102,56,176,79,222,186,251,182,175,86,219,190,199,236,90,41,250,41,205,18,177,132,231,109,214,47,166,132,254,132,155,249,95,126,5,66,122,98,116,165,148,171,189,242,222,163,186,210,207,102,136,170,143,7,247,126,245,36,70,29,12,232,142,4,74,170,156,83,233,170,165,215,112,161,120,138,118,207,121,99,40,87,113,33,84,43,147,234,28,101,244,3,178,41,255,167,217,148,207,201,166,86,134,43,89,93,101,221,182,12,152,133,90,251,23,198,24,146,161,158,18,0,0 };

View File

@ -1,5 +1,5 @@
const char HTML_INDEX[] PROGMEM = R"=====(
<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/controls.js></script></head> <body onload=javascript:start();> <div> <h4><div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span></h4></div> <hr> <div class=container> <div id=row class="row u-full-width"> </div> </div> </body> </html>
)=====";
const uint8_t HTML_INDEX_GZIP[863] PROGMEM = { 31,139,8,0,56,43,252,91,2,255,133,84,109,115,170,56,20,254,43,172,159,118,231,222,22,17,107,219,123,197,153,160,96,171,34,2,130,226,183,0,169,4,195,75,73,16,245,215,111,34,189,179,187,179,51,187,204,36,231,237,57,207,57,132,112,198,191,205,236,233,54,220,24,82,202,114,50,25,223,119,105,156,34,152,76,198,57,98,80,138,83,88,83,196,180,134,125,60,188,76,198,12,51,130,38,211,178,96,117,73,198,114,103,118,200,2,230,72,59,99,212,86,101,205,164,152,67,80,193,180,94,139,19,150,106,9,58,227,24,61,220,141,239,18,46,48,195,144,60,208,24,18,164,41,189,201,152,224,226,36,213,136,104,61,154,242,244,184,97,18,230,20,61,41,173,209,135,150,64,6,127,224,28,30,145,92,21,199,159,17,164,104,52,252,142,3,221,118,219,254,114,126,44,1,127,214,158,159,26,254,145,107,186,48,129,51,5,150,144,229,202,121,221,10,69,159,39,250,214,55,0,88,205,55,83,249,146,234,14,119,78,245,204,51,23,107,30,29,45,120,238,241,157,59,55,130,111,10,70,124,79,68,166,93,9,214,81,206,55,83,157,198,13,49,94,4,223,198,212,173,192,240,239,88,37,216,185,3,229,211,25,16,236,170,230,167,88,158,26,52,174,26,112,189,147,246,64,201,189,129,210,120,247,24,95,92,95,12,230,75,135,231,113,60,199,152,162,174,46,171,243,230,89,240,27,133,235,109,137,5,244,18,168,167,141,222,222,94,240,211,242,134,203,203,113,184,14,98,95,109,140,197,219,253,77,119,139,149,219,119,0,6,126,226,221,29,164,245,76,114,19,103,162,180,0,204,146,88,119,48,142,208,61,150,244,61,95,49,245,111,134,105,164,177,97,125,123,171,194,86,28,132,30,122,190,171,7,122,182,77,67,121,49,163,224,56,53,60,54,36,213,94,62,191,102,43,231,176,24,125,154,175,76,61,165,224,154,41,151,189,191,140,156,161,30,148,237,172,253,180,195,163,113,57,157,118,67,28,142,200,6,154,253,145,251,105,189,132,239,204,110,220,200,130,183,209,37,139,104,67,103,96,39,39,117,69,244,227,240,57,219,140,94,71,241,222,120,137,54,64,65,254,12,45,7,162,187,197,222,53,119,111,238,41,220,187,196,206,215,215,195,206,236,31,28,112,181,102,134,186,218,2,101,181,53,134,193,236,253,102,103,160,111,103,254,101,121,3,87,174,183,23,227,233,21,181,226,83,4,125,55,72,251,135,57,207,219,86,44,26,184,213,161,56,1,43,3,151,245,181,223,174,189,254,197,54,157,171,117,43,219,245,172,84,44,143,182,86,86,182,214,202,223,94,226,88,180,112,72,140,32,76,204,245,249,80,184,106,184,95,16,240,150,168,201,245,169,138,114,118,11,7,102,123,240,158,206,113,142,162,231,172,133,247,35,53,136,185,61,121,141,147,79,167,127,187,201,148,93,9,162,41,66,172,187,196,114,76,169,92,148,117,14,9,190,161,71,110,253,31,248,238,236,128,52,174,113,197,36,90,199,154,156,81,249,134,42,86,62,230,184,120,204,120,80,238,162,255,66,81,130,19,84,255,39,36,238,254,100,250,79,144,124,31,0,210,56,42,147,171,84,22,164,132,137,150,193,51,236,226,63,40,131,53,251,253,143,159,28,145,224,179,152,23,195,137,208,36,156,104,57,196,197,27,207,70,245,95,83,162,3,209,10,22,2,193,75,122,12,178,134,74,49,129,148,106,4,70,136,76,236,143,15,126,24,136,247,192,97,162,3,78,249,149,152,214,93,161,47,188,104,153,23,65,191,188,156,178,46,219,175,96,79,168,205,195,71,67,72,55,108,122,28,245,197,243,75,136,183,18,178,27,118,127,2,173,245,31,70,3,5,0,0 };
const char HTML_INDEX[] PROGMEM = R"=====(
<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
)=====";
const uint8_t HTML_INDEX_GZIP[916] PROGMEM = { 31,139,8,0,19,56,231,94,2,255,133,148,235,115,162,58,20,192,255,21,174,159,238,157,221,22,95,181,237,174,56,19,20,108,85,68,64,240,241,45,64,42,193,240,40,9,162,254,245,155,128,157,238,157,189,211,235,12,201,201,57,191,243,200,17,206,240,175,137,57,94,239,86,154,20,177,132,140,134,245,42,13,35,4,195,209,48,65,12,74,65,4,11,138,152,82,178,183,187,167,209,144,97,70,208,104,156,165,172,200,200,80,110,142,13,153,194,4,41,39,140,170,60,43,152,20,112,4,165,76,105,85,56,100,145,18,162,19,14,208,93,125,248,46,225,20,51,12,201,29,13,32,65,74,167,53,26,18,156,30,165,2,17,165,69,35,238,30,148,76,194,60,68,75,138,10,244,166,132,144,193,31,56,129,7,36,231,233,225,167,15,41,26,244,191,99,79,53,237,170,61,159,30,50,192,127,75,199,141,52,247,192,37,85,28,129,53,6,134,216,179,133,245,188,22,130,58,13,213,181,171,1,176,152,174,198,242,57,82,45,174,28,171,177,163,207,150,220,58,152,113,223,195,43,87,174,68,188,49,24,240,53,20,158,102,46,162,14,18,190,232,189,113,80,18,237,73,196,91,233,170,225,105,110,205,118,188,141,221,237,188,91,93,130,237,158,254,46,30,167,231,149,118,207,227,114,179,155,221,78,226,116,59,165,83,219,248,195,229,89,119,58,183,184,31,231,57,163,139,188,170,220,155,150,143,34,190,150,218,206,154,24,64,205,64,239,184,82,171,235,19,126,152,95,113,118,62,244,151,94,224,246,74,109,246,82,223,116,51,91,216,109,11,96,224,134,78,173,32,149,163,147,171,232,73,167,2,96,18,6,170,133,177,143,106,91,216,118,220,142,174,126,211,116,45,10,52,227,219,75,190,171,68,35,212,157,227,218,170,167,198,235,104,39,207,38,20,28,198,154,195,250,36,223,202,167,231,120,97,237,103,131,119,253,153,245,142,17,184,196,157,243,214,157,251,86,95,245,178,106,82,189,155,187,131,118,62,30,55,125,188,27,144,21,212,219,3,251,221,120,218,189,50,179,180,125,3,94,7,231,216,167,37,157,128,141,28,22,57,81,15,253,199,120,53,120,30,4,91,237,201,95,129,14,114,39,104,222,21,213,205,182,182,190,121,177,143,187,173,77,204,100,121,217,111,244,246,222,2,23,99,162,245,22,107,208,89,172,181,190,55,121,189,154,49,104,155,177,123,158,95,193,133,203,213,89,123,120,70,149,248,43,188,182,237,69,237,253,148,251,173,115,230,119,237,124,159,30,129,17,131,243,242,210,174,150,78,251,108,234,214,197,184,102,213,114,146,117,12,135,86,70,156,85,198,194,93,159,131,64,148,176,15,53,111,23,234,203,211,62,181,123,187,237,140,128,151,176,23,94,30,114,63,97,215,93,87,175,246,206,195,41,72,144,255,24,87,176,110,169,70,244,245,209,41,173,100,60,254,237,77,166,236,66,16,141,16,98,205,75,44,7,148,202,105,86,36,144,224,43,186,231,167,255,131,107,101,3,210,160,192,57,147,104,17,40,114,76,229,43,202,89,118,159,224,244,62,230,70,185,177,254,65,81,130,67,84,124,137,28,10,152,71,95,18,65,243,173,211,47,33,6,125,31,133,183,111,254,223,164,92,15,19,105,232,103,225,69,202,82,146,193,80,137,225,9,54,246,31,148,193,130,253,253,207,79,78,132,248,36,102,79,191,17,37,28,42,9,196,233,11,119,71,197,231,200,105,40,154,195,84,16,60,165,195,32,43,169,20,16,72,169,66,160,143,200,200,124,123,227,157,69,188,8,142,113,90,174,131,222,92,163,226,150,160,241,16,69,243,52,168,248,76,91,100,213,205,216,18,98,121,247,86,18,210,204,46,62,170,110,97,74,34,80,126,113,154,194,143,88,45,46,226,3,100,56,75,165,79,241,78,64,127,68,41,201,103,66,1,220,154,247,17,233,119,213,127,23,240,177,137,198,214,119,172,103,247,47,103,53,186,226,210,5,0,0 };

View File

@ -1,5 +1,5 @@
const char CSS_NORMALIZE[] PROGMEM = R"=====(
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
)=====";
const uint8_t CSS_NORMALIZE_GZIP[861] PROGMEM = { 31,139,8,0,56,43,252,91,2,255,149,84,237,142,155,58,16,125,149,104,171,74,183,146,137,216,237,199,94,25,221,39,137,242,99,176,7,112,227,47,217,38,155,20,241,238,119,12,132,36,219,108,165,254,2,6,123,230,204,57,103,166,75,70,15,141,179,169,104,192,40,125,230,17,108,44,34,6,213,84,133,137,69,194,83,42,162,250,133,5,200,159,125,76,252,185,44,63,87,197,27,214,7,149,30,255,29,107,39,207,131,129,208,42,203,203,17,66,82,66,35,131,168,36,50,137,9,148,142,172,81,173,0,159,148,179,249,181,15,200,26,231,18,6,214,33,200,252,104,131,235,61,51,160,44,51,104,123,102,225,200,34,138,233,70,236,13,165,63,15,82,69,175,225,204,107,237,196,97,132,94,42,199,4,216,35,68,230,131,107,3,198,200,142,84,213,173,39,149,213,202,98,49,93,168,142,152,161,129,46,64,171,214,242,26,34,230,191,115,34,110,93,250,103,39,136,153,224,116,220,127,89,83,88,103,177,234,80,181,93,162,238,118,157,146,18,237,158,37,52,244,59,225,221,185,17,134,26,196,33,247,98,101,33,156,118,129,167,64,12,123,8,104,211,8,28,168,163,35,145,195,59,71,112,6,215,167,12,33,211,86,215,97,151,84,210,184,31,106,23,136,147,162,118,41,57,195,159,253,105,35,233,21,229,88,179,72,240,108,59,43,248,54,131,170,157,150,163,108,236,28,140,233,172,145,171,68,61,138,177,123,94,130,36,25,127,65,83,45,42,109,127,188,162,217,148,35,125,30,110,16,243,79,77,83,86,51,236,79,101,89,142,209,128,214,55,41,254,37,181,99,79,40,122,127,19,125,253,254,185,154,104,190,176,84,121,23,85,86,142,7,36,142,168,225,15,185,207,153,146,243,188,216,126,71,147,115,15,75,215,197,246,37,71,148,105,23,58,136,163,120,108,39,153,120,32,239,124,25,50,131,141,118,111,124,214,100,156,141,117,113,226,51,117,248,173,244,167,177,11,67,97,220,47,162,243,148,241,42,219,242,44,51,233,145,67,213,7,225,85,113,79,41,215,74,208,39,55,10,71,198,62,212,146,76,135,44,130,241,119,3,101,156,117,164,183,64,182,190,85,87,174,8,213,88,247,212,161,101,202,250,62,49,231,211,108,125,34,132,236,206,242,136,145,89,96,152,101,80,182,163,217,76,83,134,245,99,157,181,57,211,21,222,81,69,85,107,188,84,152,83,14,211,212,78,54,108,92,48,179,81,151,19,29,173,131,205,4,100,151,206,30,255,123,154,227,79,123,118,27,164,193,194,244,46,70,82,25,69,193,225,178,27,192,123,4,42,34,144,207,73,42,209,135,72,45,120,167,136,214,176,148,220,209,188,0,97,148,251,219,226,107,112,88,46,73,108,160,215,105,185,196,249,164,96,227,68,31,11,101,45,45,140,233,222,239,241,213,44,149,7,41,179,168,229,56,29,29,110,29,106,137,7,208,227,109,63,162,67,113,32,225,223,183,14,180,27,158,242,72,174,46,89,167,243,244,190,198,114,199,246,166,198,240,180,39,116,11,55,19,180,34,122,101,139,91,241,63,60,79,107,225,254,252,176,0,159,252,119,39,3,113,46,186,199,50,100,221,27,133,90,86,127,242,255,229,226,95,141,199,67,12,87,252,115,164,16,25,134,126,212,242,135,87,36,10,23,32,239,142,71,29,77,214,157,90,34,67,94,164,206,251,49,58,173,228,38,42,77,147,176,142,199,230,197,95,37,218,126,165,117,178,217,254,120,153,30,175,121,183,104,108,209,202,71,142,89,135,240,126,240,47,179,250,251,250,77,217,189,151,189,77,147,171,193,71,228,151,151,106,249,145,151,193,82,64,178,212,13,215,130,255,3,4,241,118,208,151,7,0,0 };
const char CSS_NORMALIZE[] PROGMEM = R"=====(
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
)=====";
const uint8_t CSS_NORMALIZE_GZIP[861] PROGMEM = { 31,139,8,0,19,56,231,94,2,255,149,84,237,142,155,58,16,125,149,104,171,74,183,146,137,216,237,199,94,25,221,39,137,242,99,176,7,112,227,47,217,38,155,20,241,238,119,12,132,36,219,108,165,254,2,6,123,230,204,57,103,166,75,70,15,141,179,169,104,192,40,125,230,17,108,44,34,6,213,84,133,137,69,194,83,42,162,250,133,5,200,159,125,76,252,185,44,63,87,197,27,214,7,149,30,255,29,107,39,207,131,129,208,42,203,203,17,66,82,66,35,131,168,36,50,137,9,148,142,172,81,173,0,159,148,179,249,181,15,200,26,231,18,6,214,33,200,252,104,131,235,61,51,160,44,51,104,123,102,225,200,34,138,233,70,236,13,165,63,15,82,69,175,225,204,107,237,196,97,132,94,42,199,4,216,35,68,230,131,107,3,198,200,142,84,213,173,39,149,213,202,98,49,93,168,142,152,161,129,46,64,171,214,242,26,34,230,191,115,34,110,93,250,103,39,136,153,224,116,220,127,89,83,88,103,177,234,80,181,93,162,238,118,157,146,18,237,158,37,52,244,59,225,221,185,17,134,26,196,33,247,98,101,33,156,118,129,167,64,12,123,8,104,211,8,28,168,163,35,145,195,59,71,112,6,215,167,12,33,211,86,215,97,151,84,210,184,31,106,23,136,147,162,118,41,57,195,159,253,105,35,233,21,229,88,179,72,240,108,59,43,248,54,131,170,157,150,163,108,236,28,140,233,172,145,171,68,61,138,177,123,94,130,36,25,127,65,83,45,42,109,127,188,162,217,148,35,125,30,110,16,243,79,77,83,86,51,236,79,101,89,142,209,128,214,55,41,254,37,181,99,79,40,122,127,19,125,253,254,185,154,104,190,176,84,121,23,85,86,142,7,36,142,168,225,15,185,207,153,146,243,188,216,126,71,147,115,15,75,215,197,246,37,71,148,105,23,58,136,163,120,108,39,153,120,32,239,124,25,50,131,141,118,111,124,214,100,156,141,117,113,226,51,117,248,173,244,167,177,11,67,97,220,47,162,243,148,241,42,219,242,44,51,233,145,67,213,7,225,85,113,79,41,215,74,208,39,55,10,71,198,62,212,146,76,135,44,130,241,119,3,101,156,117,164,183,64,182,190,85,87,174,8,213,88,247,212,161,101,202,250,62,49,231,211,108,125,34,132,236,206,242,136,145,89,96,152,101,80,182,163,217,76,83,134,245,99,157,181,57,211,21,222,81,69,85,107,188,84,152,83,14,211,212,78,54,108,92,48,179,81,151,19,29,173,131,205,4,100,151,206,30,255,123,154,227,79,123,118,27,164,193,194,244,46,70,82,25,69,193,225,178,27,192,123,4,42,34,144,207,73,42,209,135,72,45,120,167,136,214,176,148,220,209,188,0,97,148,251,219,226,107,112,88,46,73,108,160,215,105,185,196,249,164,96,227,68,31,11,101,45,45,140,233,222,239,241,213,44,149,7,41,179,168,229,56,29,29,110,29,106,137,7,208,227,109,63,162,67,113,32,225,223,183,14,180,27,158,242,72,174,46,89,167,243,244,190,198,114,199,246,166,198,240,180,39,116,11,55,19,180,34,122,101,139,91,241,63,60,79,107,225,254,252,176,0,159,252,119,39,3,113,46,186,199,50,100,221,27,133,90,86,127,242,255,229,226,95,141,199,67,12,87,252,115,164,16,25,134,126,212,242,135,87,36,10,23,32,239,142,71,29,77,214,157,90,34,67,94,164,206,251,49,58,173,228,38,42,77,147,176,142,199,230,197,95,37,218,126,165,117,178,217,254,120,153,30,175,121,183,104,108,209,202,71,142,89,135,240,126,240,47,179,250,251,250,77,217,189,151,189,77,147,171,193,71,228,151,151,106,249,145,151,193,82,64,178,212,13,215,130,255,3,4,241,118,208,151,7,0,0 };

View File

@ -1,14 +1,15 @@
const char JS_SLIDER[] PROGMEM = R"=====(
function rkmd_rangeSlider(selector){var self,slider_width,slider_offset,curnt,sliderDiscrete,range,slider;self=$(selector);slider_width=self.width();slider_offset=self.offset().left;sliderDiscrete=self;sliderDiscrete.each(function(i,v){curnt=$(this);curnt.append(sliderDiscrete_tmplt());range=curnt.find('input[type="range"]');slider=curnt.find('.slider');slider_fill=slider.find('.slider-fill');slider_handle=slider.find('.slider-handle');slider_label=slider.find('.slider-label');var range_val=parseInt(range.val());slider_fill.css('width',range_val+'%');slider_handle.css('left',range_val+'%');slider_label.find('span').text(range_val);});self.on('mousedown touchstart','.slider-handle',function(e){if(e.button===2){return false;}
var parents=$(this).parents('.rkmd-slider');var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(':disabled');if(check_range===true){return false;}
$(this).addClass('is-active');var moveFu=function(e){var pageX=e.pageX||e.changedTouches[0].pageX;var slider_new_width=pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<'0')){slider_move(parents,slider_new_width,slider_width,true);}};var upFu=function(e){$(this).off(handlers);parents.find('.is-active').removeClass('is-active');};var handlers={mousemove:moveFu,touchmove:moveFu,mouseup:upFu,touchend:upFu};$(document).on(handlers);});self.on('mousedown touchstart','.slider',function(e){if(e.button===2){return false;}
var parents=$(this).parents('.rkmd-slider');var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(':disabled');if(check_range===true){return false;}
var slider_new_width=e.pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<'0')){slider_move(parents,slider_new_width,slider_width,true);}
var upFu=function(e){$(this).off(handlers);};var handlers={mouseup:upFu,touchend:upFu};$(document).on(handlers);});};function sliderDiscrete_tmplt(){var tmplt='<div class="slider">'+
function rkmd_rangeSlider(selector){var self,slider_width,slider_offset,curnt,sliderDiscrete,range,slider;self=$(selector);slider_width=self.width();slider_offset=self.offset().left;sliderDiscrete=self;sliderDiscrete.each(function(i,v){curnt=$(this);curnt.append(sliderDiscrete_tmplt());range=curnt.find('input[type="range"]');slider=curnt.find(".slider");slider_fill=slider.find(".slider-fill");slider_handle=slider.find(".slider-handle");slider_label=slider.find(".slider-label");var range_val=parseInt(range.val());slider_fill.css("width",range_val+"%");slider_handle.css("left",range_val+"%");slider_label.find("span").text(range_val);});self.on("mousedown touchstart",".slider-handle",function(e){if(e.button===2){return false;}
var parents=$(this).parents(".rkmd-slider");var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(":disabled");if(check_range===true){return false;}
$(this).addClass("is-active");var moveFu=function(e){var pageX=e.pageX||e.changedTouches[0].pageX;var slider_new_width=pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<"0")){slider_move(parents,slider_new_width,slider_width,true);}};var upFu=function(e){$(this).off(handlers);parents.find(".is-active").removeClass("is-active");};var handlers={mousemove:moveFu,touchmove:moveFu,mouseup:upFu,touchend:upFu,};$(document).on(handlers);});self.on("mousedown touchstart",".slider",function(e){if(e.button===2){return false;}
var parents=$(this).parents(".rkmd-slider");var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(":disabled");if(check_range===true){return false;}
var slider_new_width=e.pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<"0")){slider_move(parents,slider_new_width,slider_width,true);}
var upFu=function(e){$(this).off(handlers);};var handlers={mouseup:upFu,touchend:upFu,};$(document).on(handlers);});}
function sliderDiscrete_tmplt(){var tmplt='<div class="slider">'+
'<div class="slider-fill"></div>'+
'<div class="slider-handle"><div class="slider-label"><span>0</span></div></div>'+
'</div>';return tmplt;}
function slider_move(parents,newW,sliderW,send){var slider_new_val=parseInt(Math.round(newW/sliderW*100));var slider_fill=parents.find('.slider-fill');var slider_handle=parents.find('.slider-handle');var range=parents.find('input[type="range"]');slider_fill.css('width',slider_new_val+'%');slider_handle.css({'left':slider_new_val+'%','transition':'none','-webkit-transition':'none','-moz-transition':'none'});range.val(slider_new_val);if(parents.find('.slider-handle span').text()!=slider_new_val){parents.find('.slider-handle span').text(slider_new_val);var number=parents.attr('id').substring(2);if(send)websock.send('slvalue:'+slider_new_val+':'+number);}}
"</div>";return tmplt;}
function slider_move(parents,newW,sliderW,send){var slider_new_val=parseInt(Math.round((newW/sliderW)*100));var slider_fill=parents.find(".slider-fill");var slider_handle=parents.find(".slider-handle");var range=parents.find('input[type="range"]');range.next().html(newW);slider_fill.css("width",slider_new_val+"%");slider_handle.css({left:slider_new_val+"%",transition:"none","-webkit-transition":"none","-moz-transition":"none",});range.val(slider_new_val);if(parents.find(".slider-handle span").text()!=slider_new_val){parents.find(".slider-handle span").text(slider_new_val);var number=parents.attr("id").substring(2);if(send)websock.send("slvalue:"+slider_new_val+":"+number);}}
)=====";
const uint8_t JS_SLIDER_GZIP[865] PROGMEM = { 31,139,8,0,56,43,252,91,2,255,237,86,207,111,155,48,20,190,247,175,72,163,174,134,149,184,89,143,33,238,101,211,164,29,118,218,164,77,170,170,200,1,83,172,16,131,176,73,182,209,252,239,123,254,1,1,66,170,110,167,29,118,194,246,251,252,252,222,247,62,243,156,84,34,82,60,23,147,114,179,141,87,37,21,79,236,75,198,99,86,122,146,101,44,82,121,233,215,59,90,78,96,150,4,210,88,86,123,30,171,180,153,228,73,34,153,10,162,170,20,202,173,125,224,50,42,153,98,129,113,231,22,67,237,129,92,29,221,134,93,111,68,91,177,25,122,173,197,186,182,38,59,246,124,156,177,68,133,253,115,12,98,176,134,25,141,82,47,113,217,121,60,216,249,181,137,17,66,80,41,151,126,104,102,152,22,5,19,177,215,223,188,82,219,34,131,195,252,208,100,64,44,52,225,0,68,92,20,149,122,80,63,11,70,166,198,58,125,68,77,196,61,32,182,107,173,113,149,240,44,35,118,220,135,204,180,229,136,75,169,136,51,54,142,180,182,35,54,163,107,118,198,169,49,1,82,87,207,4,186,218,209,140,20,180,148,236,147,80,158,89,194,176,164,211,236,68,136,35,41,61,100,42,129,130,118,223,13,122,51,12,208,2,117,57,206,225,76,4,46,42,89,80,129,124,172,216,15,119,180,70,251,225,193,15,109,121,133,135,182,121,37,89,156,239,197,68,229,85,148,74,69,75,112,61,76,61,104,107,202,252,154,39,30,195,235,74,169,92,16,66,238,252,26,170,7,37,152,36,52,147,44,60,92,232,220,33,99,38,148,108,234,142,221,28,136,210,146,159,181,85,50,42,239,74,210,1,91,85,118,0,78,153,13,162,47,78,141,139,82,22,109,236,117,106,81,47,232,7,115,136,103,17,115,73,215,25,139,33,24,72,172,235,130,16,85,86,236,36,189,38,37,26,199,239,51,170,203,193,229,140,2,59,59,230,18,218,230,59,246,177,34,93,206,44,39,79,236,59,97,216,124,159,159,161,150,169,62,39,254,170,137,103,242,97,254,104,77,221,156,5,219,183,196,128,105,214,163,66,7,60,196,45,73,151,206,235,235,203,83,4,154,35,223,175,221,178,142,213,115,100,5,67,104,255,223,99,216,8,15,7,19,95,85,12,50,108,104,129,208,60,171,154,18,238,123,191,12,184,195,20,46,153,62,123,132,66,123,64,227,131,212,70,162,26,187,176,196,6,70,169,221,5,131,168,138,133,14,202,90,225,247,98,102,135,240,202,139,243,168,218,66,20,190,22,252,49,180,215,223,130,255,242,31,164,119,34,78,39,234,127,65,158,23,127,160,206,81,165,253,133,142,14,97,115,214,100,188,167,153,251,111,198,4,45,99,190,155,68,90,246,100,106,209,211,123,116,115,49,178,110,90,212,244,126,121,11,150,115,16,27,7,128,78,77,166,19,128,69,119,129,251,249,242,214,124,173,179,142,75,59,10,93,149,77,140,64,226,32,159,126,29,160,0,223,28,247,240,5,138,220,107,229,88,158,94,211,251,76,85,138,203,188,2,37,234,157,183,110,231,219,119,243,185,223,83,184,233,213,131,63,70,191,89,119,192,174,97,143,195,219,142,221,246,225,215,220,136,179,29,185,159,217,185,182,92,219,190,188,56,69,7,72,193,33,146,107,70,209,2,137,92,64,75,69,179,61,91,111,184,154,141,218,182,249,175,17,195,193,61,142,204,19,162,127,142,185,191,47,177,49,233,190,6,252,75,50,216,94,191,122,239,240,92,205,177,168,182,107,120,138,53,62,168,82,37,144,12,127,21,44,171,181,84,37,23,79,222,157,9,209,232,5,50,151,121,180,193,122,2,207,148,12,252,84,108,129,110,134,212,193,146,245,172,251,206,111,101,146,232,206,54,11,0,0 };
const uint8_t JS_SLIDER_GZIP[881] PROGMEM = { 31,139,8,0,150,187,70,95,2,255,237,86,77,143,218,48,16,189,243,43,88,107,187,196,93,240,210,61,18,204,165,85,165,30,122,106,165,86,90,173,144,73,156,141,69,112,162,216,129,182,44,255,189,227,143,132,36,192,106,219,83,15,61,37,246,60,143,223,204,60,123,156,84,50,210,34,151,195,114,189,137,151,37,147,79,252,75,38,98,94,6,138,103,60,210,121,137,247,91,86,14,97,148,140,149,181,44,119,34,214,105,61,200,147,68,113,61,142,170,82,106,63,247,65,168,168,228,154,143,173,59,63,25,26,15,244,250,232,54,108,123,163,198,74,236,111,208,88,156,107,103,114,255,1,38,25,79,116,216,221,199,34,122,115,132,179,40,13,18,31,93,32,198,91,188,183,28,129,130,78,133,194,161,29,17,86,20,92,198,65,119,241,82,111,138,12,54,195,161,141,128,58,104,34,0,56,18,178,168,244,131,254,89,112,138,172,21,61,142,106,198,109,32,34,110,14,53,225,36,34,203,168,251,239,66,38,198,114,196,165,76,198,25,63,143,116,182,35,54,99,43,126,193,169,53,1,210,84,207,18,93,110,89,70,11,86,42,254,73,234,192,78,17,152,50,97,182,24,146,72,169,0,217,74,160,113,179,238,22,189,233,19,116,64,83,142,75,56,203,192,179,82,5,147,8,19,205,127,248,173,13,26,135,7,28,186,242,202,0,109,242,74,241,56,223,201,161,206,171,40,85,154,149,224,186,31,250,184,169,41,199,123,145,4,156,172,42,173,115,73,41,189,199,123,168,30,148,96,152,176,76,241,240,48,48,177,67,196,92,106,85,215,157,248,49,36,202,72,126,210,84,201,170,188,45,73,15,108,84,217,2,120,101,214,136,174,56,13,46,74,121,180,118,199,169,65,189,160,31,34,128,207,44,22,138,173,50,30,3,25,8,172,237,130,82,93,86,252,36,188,58,36,22,199,239,51,102,202,33,212,132,65,118,182,220,7,180,201,183,252,99,69,219,57,115,57,121,226,223,41,39,246,251,252,12,181,76,205,62,241,87,147,120,174,30,166,143,206,212,142,89,242,93,147,24,48,77,58,169,48,132,251,184,57,109,167,243,230,230,234,20,129,166,8,227,189,159,54,92,3,159,172,113,31,218,189,123,108,54,194,195,193,242,171,138,94,132,117,90,128,90,224,84,83,194,121,239,148,1,145,86,166,72,201,205,222,103,82,232,54,168,125,208,189,149,168,193,206,92,98,199,86,169,237,9,139,168,138,153,33,229,172,112,189,184,209,33,188,14,226,60,170,54,64,3,27,197,31,185,189,254,24,252,215,127,47,188,19,117,122,85,255,11,250,28,252,129,60,207,74,237,111,132,116,24,212,155,13,207,119,53,123,3,216,127,58,154,199,98,59,140,140,240,41,242,74,88,140,110,7,103,230,93,147,90,204,239,192,114,9,226,175,232,197,25,147,235,70,139,185,233,3,139,233,252,206,126,157,179,198,37,114,127,40,244,101,182,28,79,227,233,22,2,42,240,205,39,31,190,144,35,255,94,57,214,167,211,246,62,51,157,146,50,175,64,138,129,89,122,231,151,226,183,239,166,83,220,17,185,237,215,189,91,163,219,176,91,96,223,180,207,195,155,174,221,244,226,215,28,10,247,248,32,210,180,76,76,82,189,201,44,227,203,221,186,27,243,165,150,189,55,135,116,118,138,5,209,50,169,132,73,244,12,201,92,66,171,69,147,29,95,173,133,158,28,77,232,104,219,228,191,206,25,14,53,113,243,182,232,110,99,207,245,75,41,26,182,159,9,248,138,246,150,239,95,189,182,191,175,73,188,172,54,43,120,163,213,62,152,214,37,220,246,112,219,16,85,173,148,46,133,124,10,238,45,69,43,35,8,93,229,209,154,152,1,188,95,50,240,83,241,25,186,237,103,14,166,156,103,211,144,126,3,128,124,107,46,79,11,0,0 };

File diff suppressed because one or more lines are too long

39
src/dataTabbedcontentJS.h Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -21,7 +21,7 @@ def parse_arguments(args=None):
parser = argparse.ArgumentParser(
description="Prepares ESPUI header files by minifying and gzipping HTML, JS and CSS source files.")
parser.add_argument("--auto", "--all", "-a", dest="auto", action="store_true",
help="Automatically find all source files in examples/gui/data/ and write C header files to src/")
help="Automatically find all source files in data/ and write C header files to src/")
parser.add_argument("--source", "--sources", "-s", dest="sources", default=None,
help="Sources directory containing CSS or JS files OR one specific file to minify")
parser.add_argument("--target", "-t", dest="target", default=None,
@ -120,7 +120,7 @@ def check_args(args):
sys.exit(abort)
def main(args):
args.sources = os.path.realpath(args.sources or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "examples", "gui", "data")))
args.sources = os.path.realpath(args.sources or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "data")))
args.target = os.path.realpath(args.target or os.sep.join((os.path.dirname(os.path.realpath(__file__)), "..", "src")))
check_args(args)
if os.path.isfile(args.sources):