├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── docs
└── VARIABLES.md
├── examples
└── Simple
│ └── Simple.ino
├── img
├── Bleeper.png
├── Bleeper.svg
├── diagram.ai
├── diagram.png
├── smartphone.png
└── web.png
├── keywords.txt
├── lib
└── readme.txt
├── library.json
├── library.properties
├── platformio.ini
└── src
├── Bleeper.h
├── Bleeper
├── Bleeper+Configuration.cpp
├── Bleeper+ConfigurationInterface.cpp
├── Bleeper+Connection.cpp
├── Bleeper+Storage.cpp
├── BleeperClass.cpp
├── BleeperClass.h
└── Initable.h
├── Configuration
├── BaseConfiguration.h
├── ConfigMap.cpp
├── ConfigMap.h
├── Configuration.h
├── ConfigurationDictionary.cpp
├── ConfigurationDictionary.h
├── ConfigurationMacros.h
├── RootConfiguration.h
├── StringConvertibleVariable.cpp
├── StringConvertibleVariable.h
└── Variable.h
├── ConfigurationInterface
├── ConfigurationInterface.h
└── WebServer
│ ├── BleeperWebServer.cpp
│ ├── BleeperWebServer.h
│ ├── ESP32
│ ├── ESP32DefaultWebServer.cpp
│ ├── ESP32DefaultWebServer.h
│ ├── HTTPRequest.cpp
│ └── HTTPRequest.h
│ ├── ESP8266
│ ├── ESP8266DefaultWebServer.cpp
│ └── ESP8266DefaultWebServer.h
│ └── WebPage.h
├── Connectivity
├── AP.cpp
├── AP.h
├── Connection.cpp
├── Connection.h
├── Wifi.cpp
└── Wifi.h
├── Helpers
├── Logger.cpp
├── Logger.h
├── macros.h
├── utils.cpp
└── utils.h
├── Observers
├── ConfigurationObserver.cpp
├── ConfigurationObserver.h
└── Observable.h
└── Storage
├── EEPROMHelper.h
├── SPIFFSStorage.h
├── Storage.h
└── VariablesMapStorage.h
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 | .pioenvs
34 | .piolibdeps
35 | .clang_complete
36 | .gcc-flags.json
37 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < http://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < http://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < http://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choice one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | #
39 | # script:
40 | # - platformio run
41 |
42 |
43 | #
44 | # Template #2: The project is intended to by used as a library with examples
45 | #
46 |
47 | # language: python
48 | # python:
49 | # - "2.7"
50 | #
51 | # sudo: false
52 | # cache:
53 | # directories:
54 | # - "~/.platformio"
55 | #
56 | # env:
57 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
58 | # - PLATFORMIO_CI_SRC=examples/file.ino
59 | # - PLATFORMIO_CI_SRC=path/to/test/directory
60 | #
61 | # install:
62 | # - pip install -U platformio
63 | #
64 | # script:
65 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
66 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Diego Ernst
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Bleeper is a library to manage your firmware configurations written in C++ for [ESP8266](https://github.com/esp8266/Arduino) and [ESP32](https://github.com/espressif/arduino-esp32) Arduino Platforms.
6 |
7 | - [Features](#features)
8 | - [Why Bleeper](#why-bleeper)
9 | - [Usage](#usage)
10 | - [Installation](#installation)
11 | - [Arduino IDE](#arduino-ide)
12 | - [PlatformIO IDE for Atom](#platformio-ide)
13 | - [Future Work](#future-work)
14 |
15 | ## Features
16 |
17 | - [x] Fully customizable hierarchical configuration structure
18 | - [x] Generic property types
19 | - [x] Automatic storage with property granularity (EEPROM & SPIFFS)
20 | - [x] Wifi & AP connections
21 | - [x] Configuration interfaces (web panel by default)
22 | - [x] Observe any configuration property change through the observer API
23 |
24 | ## Why Bleeper
25 |
26 | In the scenario of prototyping with hardware devices you will likely end up with a bunch of configuration settings like pin numbers, sensor thresholds, device ids, connection credentials, port numbers, and so many others.
27 | As a good programmer you decide to define these configurations in a "configuration file" with a lot of `#define` macros or constants.
28 |
29 | But... what if you want to change those values? Downloading the firmware each time is tedious. Think about the cases where you have multiple devices to configure or even worst you don't have close physical access to them.
30 |
31 | At the end you realize that you actually need some sort of "Configuration Manager" with high level features like exposing those variables on a web panel (or another type of interface), persisting some of them (usually your Wifi credentials) and so on.
32 |
33 | ## Usage
34 |
35 | Suppose that you have this configuration:
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | The above tree structure speaks by its own, what's worth to mention here is that we want `wifi.ssid` and `wifi.passwrod` to be persistent using the Bleeper storage.
48 |
49 | The C++ code will look like this:
50 |
51 | ```cpp
52 | #include "Bleeper.h"
53 |
54 | class Config: public RootConfiguration {
55 | public:
56 | stringVar(name, "Default Device Name");
57 | subconfig(WifiConfig, wifi);
58 | subconfig(LedsConfig, leds);
59 | };
60 |
61 | class WifiConfig: public Configuration {
62 | public:
63 | persistentStringVar(ssid, "MySSID");
64 | persistentStringVar(password, "MyPassword");
65 | };
66 |
67 | class LedsConfig: public Configuration {
68 | public:
69 | floatVar(calibration, 1.5);
70 | subconfig(SPIConfig, spi);
71 | };
72 |
73 | class SPIConfig: public Configuration {
74 | public:
75 | intVar(speed, 1000000);
76 | };
77 | ```
78 |
79 | Basically, per each configuration node you have to implement a subclass of `Configuration` and a `RootConfiguration` subclass for the especial root node (i.e the top level entry).
80 |
81 | > For a full documentation on how properties are defined read [here](docs/VARIABLES.md).
82 |
83 | Once we completed our configuration structure we can use it like this:
84 |
85 | ```cpp
86 | // Your Config instance
87 | Config C;
88 |
89 | void loop() {
90 | // access to your spi speed config
91 | int speed = C.leds.spi.speed
92 | }
93 |
94 | ```
95 |
96 | > Note that all variables are type-safe. You are not accessing to a generic wrapper and casting its type.
97 |
98 | The final step is to setup the Bleeper singleton instance with your `RootConfiguration` instance and specify your connections, interfaces, storage and observers.
99 |
100 | ```cpp
101 | #include "Bleeper.h"
102 |
103 | class CalibrationObserver: public ConfigurationObserver {
104 | public:
105 | void onConfigurationChanged(const ConfigurationPropertyChange value) {
106 | Serial.println("Configuration " + value.key + " changed from " + value.oldValue + " to " + value.newValue);
107 | }
108 | };
109 |
110 | Config C;
111 |
112 | void setup() {
113 |
114 | Bleeper
115 | .verbose(115200)
116 | .configuration
117 | .set(&C)
118 | .addObserver(new CalibrationObserver(), {&C.leds.calibration})
119 | .done()
120 | .configurationInterface
121 | .addDefaultWebServer()
122 | .done()
123 | .connection
124 | .setSingleConnectionFromPriorityList({
125 | new Wifi(&C.wifi.ssid, &C.wifi.password),
126 | new AP() // fallback
127 | })
128 | .done()
129 | .storage
130 | .setDefault() // EEPROM
131 | // .set(new SPIFFSStorage()) // SPIFFS
132 | .done()
133 | .init();
134 | }
135 |
136 | void loop() {
137 |
138 | Bleeper.handle();
139 |
140 | }
141 | ```
142 |
143 | Basically Bleeper exposes four entry points:
144 |
145 | 1. **Bleeper.configuration**
146 |
147 | Lets you set your `RootConfiguration` instance and add observers to changes on it. In this example we are setting the `CalibrationObserver` instance that will be only notified about changes on the `C.leds.calibration` property.
148 |
149 | 2. **Bleeper.configurationInterface**
150 |
151 | Here you can add as many `ConfigurationInterface` instances as you want. Bleeper provides a default web panel when calling `addDefaultWebServer`.
152 |
153 | 2. **Bleeper.connection**
154 |
155 | Under connection we can call `setMultipleConnections` or `setSingleConnectionFromPriorityList` (in which only one connection will be active) and provide a list of `Connection` instances. By default the `Wifi` class will observe changes on the provided credentials and retry the connection accordingly.
156 |
157 | 2. **Bleeper.storage**
158 |
159 | Lets you specify the `Storage` instance to use when saving your persistent variables. Calling `setDefault` will use the default EEPROM storage automatically. You can also use `SPIFFSStorage` or create your own instead.
160 |
161 | ## Installation
162 |
163 | ### Arduino IDE
164 |
165 | Go to Sketch > Include Library > Manage Libraries...
166 | Search for `Bleeper` and click on `Install`
167 |
168 | ### PlatformIO IDE
169 |
170 | Go to your `platformio.ini` file and add the following lines:
171 | ```
172 | lib_deps = Bleeper
173 | lib_ldf_mode = deep
174 | ```
175 |
176 | ## Future Work
177 |
178 | - Add support for other boards.
179 | - Improve documentation & examples.
180 | - Add CI server & tests.
181 |
182 | ## Author
183 |
184 | * [Diego Ernst](https://github.com/dernster)
185 |
--------------------------------------------------------------------------------
/docs/VARIABLES.md:
--------------------------------------------------------------------------------
1 | # Variables
2 |
3 | Variables within a `Configuration` class or `RootConfiguration` class will be tracked by `Bleeper` only if they are declared using specific macros.
4 |
5 | ## Common types
6 |
7 | - `intVar`, `floatVar` & `stringVar`
8 | They all receive two parameters, the first one is the name of the variable and the second one its default value. Default values must be of types `int`, `float` and `String` respectively.
9 |
10 | - `persistentIntVar`, `persistentFloatVar` & `persistentStringVar`
11 | The same as before but they will be persisted on the configured `Bleeper` storage.
12 |
13 | ```Cpp
14 | class ExampleConfig: public Configuration {
15 | public:
16 | persistentStringVar(boardName, "Board 1");
17 | floatVar(threshold, 0.7);
18 | };
19 | ```
20 |
21 | ## Custom types
22 |
23 | `Bleeper` allows you to store any type of variable. You only need to be able to serialize & deserialize it to & from a string.
24 |
25 | - `var(type, name, default, setBody, getBody)`
26 | - `type`: your custom type.
27 | - `name`: name of your variable.
28 | - `default`: default value.
29 | - `setBody`: scope enclosed by curly brackets in which you will have exposed a variable called `name` (your actual variable) and a constant called `nameString` which you will have to make your conversion from.
30 | - `getBody`: similar to `setBody` but you need to write the variable called `nameString` from your variable `name`.
31 |
32 |
33 | - `persistentVar(type, name, default, setBody, getBody)`
34 | The same as before but persistent.
35 |
36 | ```Cpp
37 | #include "Bleeper.h"
38 |
39 | class Point {
40 | public:
41 | int x, y;
42 |
43 | Point(int x, int y) {
44 | this->x = x;
45 | this->y = y;
46 | }
47 |
48 | Point(String string) {
49 | auto strings = splitString(string, ",");
50 | x = strings[0].toInt();
51 | y = strings[1].toInt();
52 | }
53 |
54 | String toString() {
55 | return String(x) + "," + String(y)
56 | }
57 | }
58 |
59 | class ExampleConfig: public Configuration {
60 | public:
61 | var(Point, point, Point(0, 0),
62 | {
63 | point = Point(pointString);
64 | },
65 | {
66 | pointString = point.toString();
67 | });
68 | };
69 | ```
70 |
--------------------------------------------------------------------------------
/examples/Simple/Simple.ino:
--------------------------------------------------------------------------------
1 | #include "Bleeper.h"
2 |
3 | class Network: public Configuration {
4 | public:
5 | stringVar(ip, "localhost");
6 | intVar(port, 506);
7 | };
8 |
9 | class WifiConfig: public Configuration {
10 | public:
11 | persistentStringVar(ssid, "ssid");
12 | persistentStringVar(password, "pass");
13 | subconfig(Network, network);
14 | };
15 |
16 | class Config: public RootConfiguration {
17 | public:
18 | floatVar(floatValue, 0);
19 |
20 | var(unsigned int, time, 25,
21 | {
22 | time = timeString.toInt();
23 | },
24 | {
25 | timeString = String(time);
26 | });
27 |
28 | subconfig(WifiConfig, wifi);
29 | } C;
30 |
31 | class MyObserver: public ConfigurationObserver {
32 | public:
33 | void onConfigurationChanged(const ConfigurationPropertyChange value) {
34 | Serial.println("Configuration " + value.key + " changed from " + value.oldValue + " to " + value.newValue);
35 | }
36 | };
37 |
38 | void setup() {
39 |
40 | Bleeper
41 | .verbose(115200)
42 | .configuration
43 | .set(&C)
44 | .addObserver(new MyObserver(), {&C.wifi.network.port})
45 | .done()
46 | .configurationInterface
47 | .addDefaultWebServer()
48 | .done()
49 | .connection
50 | .setSingleConnectionFromPriorityList({
51 | new Wifi(&C.wifi.ssid, &C.wifi.password),
52 | new AP()
53 | })
54 | .done()
55 | .storage
56 | .setDefault() // EEPROM
57 | // .set(new SPIFFSStorage()) // SPIFFS
58 | .done()
59 | .init();
60 | }
61 |
62 | void loop() {
63 |
64 | Bleeper.handle();
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/img/Bleeper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/workilabs/Bleeper/81992601756e2a9f4b7416ef4783f0c211536fcb/img/Bleeper.png
--------------------------------------------------------------------------------
/img/Bleeper.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/diagram.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/workilabs/Bleeper/81992601756e2a9f4b7416ef4783f0c211536fcb/img/diagram.ai
--------------------------------------------------------------------------------
/img/diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/workilabs/Bleeper/81992601756e2a9f4b7416ef4783f0c211536fcb/img/diagram.png
--------------------------------------------------------------------------------
/img/smartphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/workilabs/Bleeper/81992601756e2a9f4b7416ef4783f0c211536fcb/img/smartphone.png
--------------------------------------------------------------------------------
/img/web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/workilabs/Bleeper/81992601756e2a9f4b7416ef4783f0c211536fcb/img/web.png
--------------------------------------------------------------------------------
/keywords.txt:
--------------------------------------------------------------------------------
1 | #############################
2 | # Automatically generated
3 | #############################
4 |
5 | BleeperClass::ConfigurationInterfaceFunctions KEYWORD1
6 | add KEYWORD2
7 | addDefaultWebServer KEYWORD2
8 | BleeperClass::StorageFunctions KEYWORD1
9 | persist KEYWORD2
10 | set KEYWORD2
11 | setDefault KEYWORD2
12 | BleeperClass::UserProperties KEYWORD1
13 | BleeperClass::ConfigurationFunctions KEYWORD1
14 | addObserver KEYWORD2
15 | enableObservers KEYWORD2
16 | get KEYWORD2
17 | getAsDictionary KEYWORD2
18 | getVariables KEYWORD2
19 | set KEYWORD2
20 | setFromDictionary KEYWORD2
21 | BleeperClass::Chainable KEYWORD1
22 | done KEYWORD2
23 | BleeperClass KEYWORD1
24 | handle KEYWORD2
25 | init KEYWORD2
26 | shared KEYWORD2
27 | verbose KEYWORD2
28 | BleeperClass::ConnectionFunctions KEYWORD1
29 | set KEYWORD2
30 | setMultipleConnections KEYWORD2
31 | setSingleConnectionFromPriorityList KEYWORD2
32 | Initable KEYWORD1
33 | init KEYWORD2
34 | BaseConfiguration KEYWORD1
35 | addTo KEYWORD2
36 | fillConfigMap KEYWORD2
37 | getPrefix KEYWORD2
38 | withPrefix KEYWORD2
39 | ConfigMap KEYWORD1
40 | add KEYWORD2
41 | Configuration KEYWORD1
42 | ConfigurationDictionary KEYWORD1
43 | append KEYWORD2
44 | toStrings KEYWORD2
45 | RootConfiguration KEYWORD1
46 | getAsDictionary KEYWORD2
47 | getVariableForAddress KEYWORD2
48 | getVariables KEYWORD2
49 | init KEYWORD2
50 | isAddressValid KEYWORD2
51 | setFromDictionary KEYWORD2
52 | StringConvertibleVariable KEYWORD1
53 | getAsString KEYWORD2
54 | getFullKey KEYWORD2
55 | getKey KEYWORD2
56 | getMemoryAddress KEYWORD2
57 | isPersistentVariable KEYWORD2
58 | setFromString KEYWORD2
59 | setFullKey KEYWORD2
60 | Variable KEYWORD1
61 | addTo KEYWORD2
62 | getAsString KEYWORD2
63 | isPersistentVariable KEYWORD2
64 | setFromString KEYWORD2
65 | IntVariable KEYWORD1
66 | getAsString KEYWORD2
67 | setFromString KEYWORD2
68 | GenericVariable KEYWORD1
69 | SetterOfType KEYWORD2
70 | getAsString KEYWORD2
71 | setFromString KEYWORD2
72 | StringVariable KEYWORD1
73 | getAsString KEYWORD2
74 | setFromString KEYWORD2
75 | FloatVariable KEYWORD1
76 | getAsString KEYWORD2
77 | setFromString KEYWORD2
78 | ConfigurationInterface KEYWORD1
79 | handle KEYWORD2
80 | init KEYWORD2
81 | AP KEYWORD1
82 | connect KEYWORD2
83 | disconnect KEYWORD2
84 | handle KEYWORD2
85 | init KEYWORD2
86 | Connections KEYWORD1
87 | add KEYWORD2
88 | handle KEYWORD2
89 | init KEYWORD2
90 | OneOfMultipleConnection KEYWORD1
91 | connect KEYWORD2
92 | disconnect KEYWORD2
93 | disconnectFromAllExepct KEYWORD2
94 | handle KEYWORD2
95 | retry KEYWORD2
96 | Connection KEYWORD1
97 | connect KEYWORD2
98 | connectionDidComplete KEYWORD2
99 | connectionDidFail KEYWORD2
100 | disconnect KEYWORD2
101 | handle KEYWORD2
102 | init KEYWORD2
103 | retry KEYWORD2
104 | setIsExclusiveConnection KEYWORD2
105 | wantsToRetryConnection KEYWORD2
106 | MultipleConnection KEYWORD1
107 | connect KEYWORD2
108 | disconnect KEYWORD2
109 | handle KEYWORD2
110 | Wifi KEYWORD1
111 | connect KEYWORD2
112 | disconnect KEYWORD2
113 | handle KEYWORD2
114 | init KEYWORD2
115 | onConfigurationChanged KEYWORD2
116 | retry KEYWORD2
117 | wantsToRetryConnection KEYWORD2
118 | Logger KEYWORD1
119 | print KEYWORD2
120 | ConfigurationObserver KEYWORD1
121 | isInterestedIn KEYWORD2
122 | onConfigurationChanged KEYWORD2
123 | setFilter KEYWORD2
124 | ConfigurationPropertyChange KEYWORD1
125 | Observable KEYWORD1
126 | addObserver KEYWORD2
127 | EEPROMHelper KEYWORD1
128 | readStrings KEYWORD2
129 | writeStrings KEYWORD2
130 | Storage KEYWORD1
131 | load KEYWORD2
132 | persist KEYWORD2
133 | VariablesMapStorage KEYWORD1
134 | init KEYWORD2
135 | load KEYWORD2
136 | persist KEYWORD2
137 | DefaultWebServer KEYWORD1
138 | handle KEYWORD2
139 | init KEYWORD2
140 | WebServer KEYWORD1
141 | handle KEYWORD2
142 | init KEYWORD2
143 |
144 | #############################
145 | # Manual settings
146 | #############################
147 |
148 | Bleeper KEYWORD1
149 | var KEYWORD2
150 | floatVar KEYWORD2
151 | stringVar KEYWORD2
152 | intVar KEYWORD2
153 | persistentVar KEYWORD2
154 | persistentFloatVar KEYWORD2
155 | persistentStringVar KEYWORD2
156 | persistentIntVar KEYWORD2
157 | subconfig KEYWORD2
158 |
--------------------------------------------------------------------------------
/lib/readme.txt:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for the project specific (private) libraries.
3 | PlatformIO will compile them to static libraries and link to executable file.
4 |
5 | The source code of each library should be placed in separate directory, like
6 | "lib/private_lib/[here are source files]".
7 |
8 | For example, see how can be organized `Foo` and `Bar` libraries:
9 |
10 | |--lib
11 | | |--Bar
12 | | | |--docs
13 | | | |--examples
14 | | | |--src
15 | | | |- Bar.c
16 | | | |- Bar.h
17 | | |--Foo
18 | | | |- Foo.c
19 | | | |- Foo.h
20 | | |- readme.txt --> THIS FILE
21 | |- platformio.ini
22 | |--src
23 | |- main.c
24 |
25 | Then in `src/main.c` you should use:
26 |
27 | #include
28 | #include
29 |
30 | // rest H/C/CPP code
31 |
32 | PlatformIO will find your libraries automatically, configure preprocessor's
33 | include paths and build them.
34 |
35 | More information about PlatformIO Library Dependency Finder
36 | - http://docs.platformio.org/page/librarymanager/ldf.html
37 |
--------------------------------------------------------------------------------
/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Bleeper",
3 | "keywords": "Configuration, Storage, Web Panel, Connection, WiFi",
4 | "description": "A library to store generic configurations",
5 | "repository":
6 | {
7 | "type": "git",
8 | "url": "https://github.com/neman-io/Bleeper.git"
9 | },
10 | "frameworks": "arduino",
11 | "platforms": ["espressif8266", "espressif32"],
12 | "version": "1.1.0"
13 | }
14 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=Bleeper
2 | version=1.1.0
3 | author=Diego Ernst
4 | maintainer=Diego Ernst
5 | sentence=A library to store generic configurations.
6 | paragraph=Easily define your configuration hierarchy, the type of each property and weather or not it should be persisted.
7 | category=Other
8 | url=https://github.com/neman-io/Bleeper.git
9 | architectures=esp8266,esp32
10 | includes=Bleeper.h
11 |
--------------------------------------------------------------------------------
/platformio.ini:
--------------------------------------------------------------------------------
1 | #
2 | # Project Configuration File
3 | #
4 | # A detailed documentation with the EXAMPLES is located here:
5 | # http://docs.platformio.org/en/latest/projectconf.html
6 | #
7 |
8 | # A sign `#` at the beginning of the line indicates a comment
9 | # Comment lines are ignored.
10 |
11 | # Simple and base environment
12 | # [env:mybaseenv]
13 | # platform = %INSTALLED_PLATFORM_NAME_HERE%
14 | # framework =
15 | # board =
16 | #
17 | # Automatic targets - enable auto-uploading
18 | # targets = upload
19 |
20 | [env:esp8266dev]
21 | platform = espressif
22 | framework = arduino
23 | board = nodemcuv2
24 |
25 | [env:esp32dev]
26 | platform = espressif32
27 | framework = arduino
28 | board = esp32dev
29 |
--------------------------------------------------------------------------------
/src/Bleeper.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Helpers/utils.h"
4 | #include "Bleeper/BleeperClass.h"
5 | #include "Connectivity/Wifi.h"
6 | #include "Connectivity/AP.h"
7 | #include "Observers/ConfigurationObserver.h"
8 | #include "Configuration/ConfigurationMacros.h"
9 | #include "Configuration/Configuration.h"
10 | #include "Configuration/RootConfiguration.h"
11 | #include "Storage/SPIFFSStorage.h"
12 |
--------------------------------------------------------------------------------
/src/Bleeper/Bleeper+Configuration.cpp:
--------------------------------------------------------------------------------
1 | #include "Bleeper/BleeperClass.h"
2 | #include "Observers/ConfigurationObserver.h"
3 | #include "Helpers/macros.h"
4 |
5 | #define FunctionsContainer BleeperClass::ConfigurationFunctions
6 |
7 | FunctionsContainer& FunctionsContainer::addObserver(ConfigurationObserver* observer, std::set filter) {
8 | guard(Bleeper.userProperties.rootConfig != NULL, return *this);
9 | observer->setFilter(filter);
10 | Bleeper.userProperties.rootConfig->addObserver(observer);
11 | return *this;
12 | }
13 |
14 | FunctionsContainer& FunctionsContainer::set(RootConfiguration* config) {
15 | Bleeper.userProperties.rootConfig = config;
16 | return *this;
17 | }
18 |
19 | void FunctionsContainer::setFromDictionary(const ConfigurationDictionary& dict) {
20 | Bleeper.userProperties.rootConfig->setFromDictionary(dict);
21 | }
22 |
23 | ConfigurationDictionary FunctionsContainer::getAsDictionary(bool onlyPersistent) {
24 | guard(Bleeper.userProperties.rootConfig, return ConfigurationDictionary());
25 | return Bleeper.userProperties.rootConfig->getAsDictionary(onlyPersistent);
26 | }
27 |
28 | RootConfiguration* FunctionsContainer::get() {
29 | return Bleeper.userProperties.rootConfig;
30 | }
31 |
32 | void FunctionsContainer::enableObservers(bool enable) {
33 | ConfigurationObserver::isEnabled = enable;
34 | }
35 |
36 | const std::vector& FunctionsContainer::getVariables() {
37 | return Bleeper.userProperties.rootConfig->getVariables();
38 | }
39 |
--------------------------------------------------------------------------------
/src/Bleeper/Bleeper+ConfigurationInterface.cpp:
--------------------------------------------------------------------------------
1 | #ifdef ESP8266
2 | #include "ConfigurationInterface/WebServer/ESP8266/ESP8266DefaultWebServer.h"
3 | #elif ESP32
4 | #include "ConfigurationInterface/WebServer/ESP32/ESP32DefaultWebServer.h"
5 | #endif
6 |
7 | #include "Bleeper/BleeperClass.h"
8 | #include "Helpers/macros.h"
9 |
10 | #define FunctionsContainer BleeperClass::ConfigurationInterfaceFunctions
11 |
12 | FunctionsContainer& FunctionsContainer::add(ConfigurationInterface* i) {
13 | Bleeper.userProperties.interfaces.push_back(i);
14 | return *this;
15 | }
16 |
17 | FunctionsContainer& FunctionsContainer::addDefaultWebServer() {
18 | #ifdef ESP8266
19 | Bleeper.userProperties.interfaces.push_back(new ESP8266DefaultWebServer(80));
20 | #elif ESP32
21 | Bleeper.userProperties.interfaces.push_back(new ESP32DefaultWebServer(80));
22 | #endif
23 | return *this;
24 | }
25 |
--------------------------------------------------------------------------------
/src/Bleeper/Bleeper+Connection.cpp:
--------------------------------------------------------------------------------
1 | #include "Bleeper/BleeperClass.h"
2 | #include "Helpers/macros.h"
3 |
4 | #define FunctionsContainer BleeperClass::ConnectionFunctions
5 |
6 | FunctionsContainer& FunctionsContainer::set(Connection* c) {
7 | Bleeper.userProperties.connection = c;
8 | return *this;
9 | }
10 |
11 | FunctionsContainer& FunctionsContainer::setMultipleConnections(std::vector connections) {
12 | Bleeper.userProperties.connection = new MultipleConnection(connections);
13 | return *this;
14 | }
15 |
16 | FunctionsContainer& FunctionsContainer::setSingleConnectionFromPriorityList(std::vector connections) {
17 | Bleeper.userProperties.connection = new OneOfMultipleConnection(connections);
18 | return *this;
19 | }
20 |
21 | Connection* FunctionsContainer::get() {
22 | return Bleeper.userProperties.connection;
23 | }
24 |
--------------------------------------------------------------------------------
/src/Bleeper/Bleeper+Storage.cpp:
--------------------------------------------------------------------------------
1 | #include "Bleeper/BleeperClass.h"
2 | #include "Storage/VariablesMapStorage.h"
3 | #include "Helpers/macros.h"
4 |
5 | #define FunctionsContainer BleeperClass::StorageFunctions
6 |
7 | FunctionsContainer& FunctionsContainer::set(Storage* s) {
8 | Bleeper.userProperties.storage = s;
9 | return *this;
10 | }
11 |
12 | FunctionsContainer& FunctionsContainer::setDefault() {
13 | Bleeper.userProperties.storage = new VariablesMapStorage();
14 | return *this;
15 | }
16 |
17 | FunctionsContainer& FunctionsContainer::persist() {
18 | guard(Bleeper.userProperties.storage, return *this);
19 | Bleeper.userProperties.storage->persist();
20 | return *this;
21 | }
22 |
--------------------------------------------------------------------------------
/src/Bleeper/BleeperClass.cpp:
--------------------------------------------------------------------------------
1 | #include "Bleeper/BleeperClass.h"
2 | #include "Helpers/Logger.h"
3 | #include "Helpers/macros.h"
4 |
5 | #ifdef ESP8266
6 | #include
7 | #elif ESP32
8 | #include
9 | #endif
10 |
11 | BleeperClass* BleeperClass::sharedInstance = NULL;
12 |
13 | BleeperClass::BleeperClass() {
14 | userProperties.storage = NULL;
15 | userProperties.rootConfig = NULL;
16 | userProperties.connection = NULL;
17 | }
18 |
19 | BleeperClass* BleeperClass::shared() {
20 | if (!sharedInstance)
21 | sharedInstance = new BleeperClass();
22 | return sharedInstance;
23 | }
24 |
25 | void BleeperClass::handle() {
26 | for(auto interface: userProperties.interfaces) {
27 | interface->handle();
28 | }
29 |
30 | if (userProperties.connection) {
31 | userProperties.connection->handle();
32 | }
33 |
34 | }
35 |
36 | BleeperClass& BleeperClass::verbose() {
37 | Logger::verbose = true;
38 | return *this;
39 | }
40 |
41 | BleeperClass& BleeperClass::verbose(int baudRate) {
42 | Logger::verbose = true;
43 | Logger::baudRate = baudRate;
44 | return *this;
45 | }
46 |
47 | void BleeperClass::init() {
48 | init(true);
49 | }
50 |
51 | void BleeperClass::init(bool loadFromStorage) {
52 | guard(userProperties.rootConfig, return);
53 |
54 | configuration.enableObservers(false);
55 |
56 | userProperties.rootConfig->init();
57 |
58 | if (userProperties.storage) {
59 | userProperties.storage->init();
60 | if (loadFromStorage)
61 | userProperties.storage->load();
62 | }
63 |
64 | for(auto interface: userProperties.interfaces) {
65 | interface->init();
66 | }
67 |
68 | if (userProperties.connection) {
69 | WiFi.mode(WIFI_OFF);
70 | userProperties.connection->init();
71 | userProperties.connection->connect();
72 | }
73 | configuration.enableObservers(true);
74 | }
75 |
--------------------------------------------------------------------------------
/src/Bleeper/BleeperClass.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Storage/Storage.h"
3 | #include "Configuration/RootConfiguration.h"
4 | #include "Connectivity/Connection.h"
5 | #include "Configuration/ConfigurationDictionary.h"
6 | #include "ConfigurationInterface/ConfigurationInterface.h"
7 | #include "Bleeper/Initable.h"
8 |
9 | #define Bleeper (*BleeperClass::shared())
10 |
11 | class BleeperClass: public Initable {
12 | private:
13 | static BleeperClass* sharedInstance;
14 | BleeperClass();
15 |
16 | struct UserProperties {
17 | Storage* storage;
18 | RootConfiguration* rootConfig;
19 | std::vector interfaces;
20 | Connection* connection;
21 | } userProperties;
22 |
23 | public:
24 | static BleeperClass* shared();
25 | void handle();
26 | void init();
27 | void init(bool loadFromStorage);
28 | BleeperClass& verbose();
29 | BleeperClass& verbose(int baudRate);
30 |
31 | class Chainable {
32 | public:
33 | BleeperClass& done() {
34 | return Bleeper;
35 | }
36 | };
37 |
38 | class ConfigurationFunctions: public Chainable {
39 | public:
40 | ConfigurationFunctions& set(RootConfiguration*);
41 | ConfigurationFunctions& addObserver(ConfigurationObserver* observer, std::set filter = std::set());
42 | RootConfiguration* get();
43 | ConfigurationDictionary getAsDictionary(bool onlyPersistent = false);
44 | const std::vector& getVariables();
45 | void enableObservers(bool);
46 | void setFromDictionary(const ConfigurationDictionary&);
47 | } configuration;
48 |
49 | class ConnectionFunctions: public Chainable {
50 | public:
51 | ConnectionFunctions& set(Connection*);
52 | Connection* get();
53 | ConnectionFunctions& setMultipleConnections(std::vector connections);
54 | ConnectionFunctions& setSingleConnectionFromPriorityList(std::vector connections);
55 | } connection;
56 |
57 | class StorageFunctions: public Chainable {
58 | public:
59 | StorageFunctions& set(Storage*);
60 | StorageFunctions& setDefault();
61 | StorageFunctions& persist();
62 | } storage;
63 |
64 | class ConfigurationInterfaceFunctions: public Chainable {
65 | public:
66 | ConfigurationInterfaceFunctions& add(ConfigurationInterface*);
67 | ConfigurationInterfaceFunctions& addDefaultWebServer();
68 | } configurationInterface;
69 |
70 | };
71 |
--------------------------------------------------------------------------------
/src/Bleeper/Initable.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | class Initable {
4 | public:
5 | virtual void init() = 0;
6 | };
7 |
--------------------------------------------------------------------------------
/src/Configuration/BaseConfiguration.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Configuration/ConfigurationDictionary.h"
3 | #include "Variable.h"
4 | #include "StringConvertibleVariable.h"
5 | #include "Configuration/ConfigMap.h"
6 |
7 | class BaseConfiguration {
8 | protected:
9 | String prefix;
10 | std::vector vars;
11 | std::vector subConfigs;
12 |
13 | template void add(Variable& var) {
14 | vars.push_back(&var);
15 | }
16 |
17 | void fillConfigMap(String cumulativePrefix, ConfigMap* map) {
18 | for(StringConvertibleVariable* variable: vars) {
19 | auto prefix = cumulativePrefix;
20 | auto varFullKey = (prefix != "") ? prefix + "." + variable->getKey() : variable->getKey();
21 | variable->setFullKey(varFullKey);
22 | map->add(variable->getMemoryAddress(), variable);
23 | }
24 | for(BaseConfiguration* subConfig: subConfigs) {
25 | auto cumulative = (cumulativePrefix != "") ? cumulativePrefix + "." + subConfig->prefix: subConfig->prefix;
26 | subConfig->fillConfigMap(cumulative, map);
27 | }
28 | }
29 |
30 | public:
31 | BaseConfiguration() {}
32 |
33 | String getPrefix() {
34 | return prefix;
35 | }
36 |
37 | void fillConfigMap(ConfigMap* map) {
38 | fillConfigMap("", map);
39 | }
40 |
41 | template
42 | T* addTo(std::vector& subConfigs) {
43 | subConfigs.push_back(this);
44 | return (T*)this;
45 | }
46 |
47 | template
48 | T* withPrefix(String prefix) {
49 | this->prefix = prefix;
50 | return (T*)this;
51 | }
52 |
53 | };
54 |
--------------------------------------------------------------------------------
/src/Configuration/ConfigMap.cpp:
--------------------------------------------------------------------------------
1 | #include "ConfigMap.h"
2 |
3 | ConfigMap::ConfigMap() {}
4 |
5 | void ConfigMap::add(VariableAddress address, StringConvertibleVariable* variable) {
6 | addressMap[address] = variable;
7 | keyMap[variable->getFullKey()] = variable;
8 | variables.push_back(variable);
9 | }
10 |
--------------------------------------------------------------------------------
/src/Configuration/ConfigMap.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "StringConvertibleVariable.h"
3 | #include "Configuration/ConfigurationDictionary.h"
4 | #include