supla-device
Loading...
Searching...
No Matches
custom_parameter.h
1/*
2 * Copyright (C) AC SOFTWARE SP. Z O.O
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19#ifndef SRC_SUPLA_NETWORK_HTML_CUSTOM_PARAMETER_H_
20#define SRC_SUPLA_NETWORK_HTML_CUSTOM_PARAMETER_H_
21
22#ifndef ARDUINO_ARCH_AVR
23
24#include <inttypes.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <string.h>
28#include <supla/network/html_element.h>
29#include <supla/network/web_sender.h>
30#include <supla/storage/config.h>
31#include <supla/storage/storage.h>
32#include <supla/tools.h>
33
34#include <limits>
35#include <type_traits>
36
37namespace Supla {
38
39namespace Html {
40
46template <typename T>
47class CustomParameterTemplate : public HtmlElement {
48 public:
49 CustomParameterTemplate(const char* paramTag,
50 const char* paramLabel,
51 T defaultValue = static_cast<T>(0),
52 T minValue = std::numeric_limits<T>::lowest(),
53 T maxValue = std::numeric_limits<T>::max(),
54 uint8_t decimalPlaces = 0);
55
56 virtual ~CustomParameterTemplate();
57
58 void send(Supla::WebSender* sender) override;
59 bool handleResponse(const char* key, const char* value) override;
60
61 T getParameterValue();
62 void setParameterValue(T newValue);
63
64 protected:
65 static_assert(
66 (std::is_integral<T>::value && std::is_signed<T>::value) ||
67 std::is_floating_point<T>::value,
68 "CustomParameterTemplate supports signed integers and floating types");
69
70 int32_t parameterValue = 0;
71 char* tag = nullptr;
72 char* label = nullptr;
73 int32_t minStoredValue = 0;
74 int32_t maxStoredValue = 0;
75 uint8_t decimalPlaces = 0;
76
77 static uint8_t sanitizeDecimalPlaces(uint8_t requestedDecimalPlaces);
78 static int32_t getScaleFactor(uint8_t decimalPlaces);
79 static int32_t clampToInt32(long double value);
80
81 int32_t encodeValue(T value) const;
82 T decodeValue(int32_t value) const;
83 void setStoredValue(int32_t newValue, bool saveToConfig);
84};
85
86template <typename T>
87CustomParameterTemplate<T>::CustomParameterTemplate(const char* paramTag,
88 const char* paramLabel,
89 T defaultValue,
90 T minValue,
91 T maxValue,
92 uint8_t decimalPlaces)
93: HtmlElement(HTML_SECTION_FORM),
94decimalPlaces(sanitizeDecimalPlaces(decimalPlaces)) {
95 if (paramTag != nullptr) {
96 int size = strlen(paramTag);
97 if (size < 500) {
98 tag = new char[size + 1];
99 strncpy(tag, paramTag, size + 1);
100 }
101 }
102
103 if (paramLabel != nullptr) {
104 int size = strlen(paramLabel);
105 if (size < 500) {
106 label = new char[size + 1];
107 strncpy(label, paramLabel, size + 1);
108 }
109 }
110
111 minStoredValue = encodeValue(minValue);
112 maxStoredValue = encodeValue(maxValue);
113 if (minStoredValue > maxStoredValue) {
114 const int32_t tmp = minStoredValue;
115 minStoredValue = maxStoredValue;
116 maxStoredValue = tmp;
117 }
118
119 setStoredValue(encodeValue(defaultValue), false);
120}
121
122template <typename T>
123CustomParameterTemplate<T>::~CustomParameterTemplate() {
124 if (tag != nullptr) {
125 delete[] tag;
126 tag = nullptr;
127 }
128 if (label != nullptr) {
129 delete[] label;
130 label = nullptr;
131 }
132}
133
134template <typename T>
135uint8_t CustomParameterTemplate<T>::sanitizeDecimalPlaces(
136 uint8_t requestedDecimalPlaces) {
137 if (std::is_integral<T>::value) {
138 return 0;
139 }
140 return requestedDecimalPlaces > 6 ? 6 : requestedDecimalPlaces;
141}
142
143template <typename T>
144int32_t CustomParameterTemplate<T>::getScaleFactor(uint8_t decimalPlaces) {
145 int32_t factor = 1;
146 for (uint8_t i = 0; i < decimalPlaces; i++) {
147 factor *= 10;
148 }
149 return factor;
150}
151
152template <typename T>
153int32_t CustomParameterTemplate<T>::clampToInt32(long double value) {
154 if (value > static_cast<long double>(INT32_MAX)) {
155 return INT32_MAX;
156 }
157 if (value < static_cast<long double>(INT32_MIN)) {
158 return INT32_MIN;
159 }
160 return static_cast<int32_t>(value);
161}
162
163template <typename T>
164int32_t CustomParameterTemplate<T>::encodeValue(T value) const {
165 if (std::is_integral<T>::value) {
166 return clampToInt32(static_cast<long double>(value));
167 }
168
169 const long double scale =
170 static_cast<long double>(getScaleFactor(decimalPlaces));
171 long double scaled = static_cast<long double>(value) * scale;
172 if (scaled >= 0) {
173 scaled += 0.5;
174 } else {
175 scaled -= 0.5;
176 }
177 return clampToInt32(scaled);
178}
179
180template <typename T>
181T CustomParameterTemplate<T>::decodeValue(int32_t value) const {
182 if (std::is_integral<T>::value) {
183 return static_cast<T>(value);
184 }
185
186 return static_cast<T>(static_cast<long double>(value) /
187 getScaleFactor(decimalPlaces));
188}
189
190template <typename T>
191void CustomParameterTemplate<T>::setStoredValue(int32_t newValue,
192 bool saveToConfig) {
193 if (newValue < minStoredValue) {
194 newValue = minStoredValue;
195 }
196 if (newValue > maxStoredValue) {
197 newValue = maxStoredValue;
198 }
199
200 parameterValue = newValue;
201
202 auto cfg = Supla::Storage::ConfigInstance();
203 if (saveToConfig && cfg) {
204 cfg->setInt32(tag, parameterValue);
205 cfg->saveWithDelay(1000);
206 }
207}
208
209template <typename T>
210void CustomParameterTemplate<T>::send(Supla::WebSender* sender) {
211 auto cfg = Supla::Storage::ConfigInstance();
212 if (cfg) {
213 int32_t storedValue = parameterValue;
214 if (cfg->getInt32(tag, &storedValue)) {
215 setStoredValue(storedValue, false);
216 }
217 }
218
219 sender->formField([&]() {
220 sender->labelFor(tag, label);
221
222 sender->voidTag("input")
223 .attr("type", "number")
224 .attr("step", 1, decimalPlaces)
225 .attr("min", minStoredValue, decimalPlaces)
226 .attr("max", maxStoredValue, decimalPlaces)
227 .attr("name", tag)
228 .attr("id", tag)
229 .attr("value", parameterValue, decimalPlaces)
230 .finish();
231 });
232}
233
234template <typename T>
235bool CustomParameterTemplate<T>::handleResponse(const char* key,
236 const char* value) {
237 if (key == nullptr || value == nullptr || tag == nullptr ||
238 strcmp(key, tag) != 0) {
239 return false;
240 }
241
242 int32_t parsedValue = 0;
243 if (std::is_integral<T>::value) {
244 parsedValue = stringToInt(value);
245 } else {
246 parsedValue = floatStringToInt(value, decimalPlaces);
247 }
248
249 setStoredValue(parsedValue, true);
250 return true;
251}
252
253template <typename T>
254T CustomParameterTemplate<T>::getParameterValue() {
255 auto cfg = Supla::Storage::ConfigInstance();
256 if (cfg) {
257 int32_t storedValue = parameterValue;
258 if (cfg->getInt32(tag, &storedValue)) {
259 setStoredValue(storedValue, false);
260 }
261 }
262 return decodeValue(parameterValue);
263}
264
265template <typename T>
266void CustomParameterTemplate<T>::setParameterValue(T newValue) {
267 setStoredValue(encodeValue(newValue), true);
268}
269
270using CustomParameter = CustomParameterTemplate<int32_t>;
271
272}; // namespace Html
273}; // namespace Supla
274
275#endif // ARDUINO_ARCH_AVR
276#endif // SRC_SUPLA_NETWORK_HTML_CUSTOM_PARAMETER_H_
Definition html_element.h:37
HtmlTag & attr(const char *name, const char *value)
Append a quoted HTML attribute with escaped value.
Definition web_sender.cpp:64
HtmlTag & finish()
Close the opening tag and mark it as finished.
Definition web_sender.cpp:113
This HTML Element provides numeric input in config mode.
Definition custom_parameter.h:47
Definition web_sender.h:175
void formField(Fn &&fn, const char *className="form-field")
Emit a <div class="form-field">...</div> block.
Definition web_sender.h:218
HtmlTag voidTag(const char *tagName)
Start a builder for a void HTML tag such as <input>.
Definition web_sender.h:379
void labelFor(const char *id, const char *text)
Emit a <label for="...">...</label> pair.
Definition web_sender.cpp:152