SensESP 3.4.1-alpha
Universal Signal K sensor toolkit ESP32
Loading...
Searching...
No Matches
digital_input.h
Go to the documentation of this file.
1#ifndef SENSESP_SENSORS_DIGITAL_INPUT_H_
2#define SENSESP_SENSORS_DIGITAL_INPUT_H_
3
4#include <elapsedMillis.h>
5
6#include "ReactESP.h"
8#include "sensesp_base_app.h"
9#include "sensor.h"
10
11namespace sensesp {
12
22 public:
23 DigitalInput(uint8_t pin, int pin_mode) : pin_{pin} {
24 pinMode(pin_, pin_mode);
25 };
26
27 protected:
28 uint8_t pin_;
29};
30
51class DigitalInputState : public DigitalInput, public Sensor<bool> {
52 public:
53 DigitalInputState(uint8_t pin, int pin_mode, int read_delay = 1000,
54 String config_path = "")
55 : DigitalInput{pin, pin_mode},
56 Sensor<bool>(config_path),
57 read_delay_{read_delay} {
58 load();
59
60 repeat_event_ = event_loop()->onRepeat(read_delay_,
61 [this]() { this->emit(digitalRead(pin_)); });
62 }
63
65 if (repeat_event_ != nullptr) {
66 repeat_event_->remove(event_loop());
67 }
68 }
69
70 private:
71 int read_delay_;
72 reactesp::RepeatEvent* repeat_event_ = nullptr;
73 virtual bool to_json(JsonObject& root) override;
74 virtual bool from_json(const JsonObject& config) override;
75};
76
77const String ConfigSchema(const DigitalInputState& obj);
78
80
99class DigitalInputCounter : public DigitalInput, public Sensor<int> {
100 public:
101 DigitalInputCounter(uint8_t pin, int pin_mode, int interrupt_type,
102 unsigned int read_delay, String config_path = "")
103 : DigitalInputCounter(pin, pin_mode, interrupt_type, read_delay,
104 config_path, [this]() { this->counter_ = this->counter_ + 1; }) {
106 }
107
109 if (repeat_event_ != nullptr) {
110 repeat_event_->remove(event_loop());
111 }
112 if (isr_event_ != nullptr) {
113 isr_event_->remove(event_loop().get());
114 }
115 }
116
117 virtual bool to_json(JsonObject& root) override;
118 virtual bool from_json(const JsonObject& config) override;
119
120 protected:
121 // load() calls the virtual from_json(). Inside a base-class constructor the
122 // dynamic type is still the base, so loading there dispatches to the base
123 // from_json() and silently drops fields a derived class adds. A derived class
124 // with extra config therefore constructs with kNo and calls load() from its
125 // own constructor body, where the full dynamic type is established.
126 enum class LoadConfig { kNo, kYes };
127
128 DigitalInputCounter(uint8_t pin, int pin_mode, int interrupt_type,
129 unsigned int read_delay, String config_path,
130 std::function<void()> interrupt_handler)
131 : DigitalInputCounter(pin, pin_mode, interrupt_type, read_delay,
132 config_path, interrupt_handler, LoadConfig::kYes) {}
133
134 DigitalInputCounter(uint8_t pin, int pin_mode, int interrupt_type,
135 unsigned int read_delay, String config_path,
136 std::function<void()> interrupt_handler,
137 LoadConfig load_config)
138 : DigitalInput{pin, pin_mode},
139 Sensor<int>(config_path),
140 read_delay_{read_delay},
141 interrupt_type_{interrupt_type},
142 interrupt_handler_{interrupt_handler} {
143 if (load_config == LoadConfig::kYes) {
144 load();
145 }
146 }
147
148 // Call after member init and after load(): registration captures read_delay_,
149 // which load() may overwrite from persisted config.
151 isr_event_ = event_loop()->onInterrupt(pin_, interrupt_type_, interrupt_handler_);
152 repeat_event_ = event_loop()->onRepeat(read_delay_, [this]() {
153 noInterrupts();
155 counter_ = 0;
156 interrupts();
157 notify();
158 });
159 }
160
161 unsigned int read_delay_;
162 volatile unsigned int counter_ = 0;
163 reactesp::RepeatEvent* repeat_event_ = nullptr;
164 reactesp::ISREvent* isr_event_ = nullptr;
165
166 private:
167 int interrupt_type_;
168 std::function<void()> interrupt_handler_;
169};
170
171const String ConfigSchema(const DigitalInputCounter& obj);
172
174
197 public:
198 DigitalInputDebounceCounter(uint8_t pin, int pin_mode, int interrupt_type,
199 unsigned int read_delay,
200 unsigned int ignore_interval_ms,
201 String config_path = "")
202 : DigitalInputCounter(pin, pin_mode, interrupt_type, read_delay,
203 config_path, [this]() { this->handleInterrupt(); },
205 ignore_interval_ms_{ignore_interval_ms} {
206 // Load here, not in the base ctor (LoadConfig::kNo above): only now is the
207 // dynamic type complete, so from_json() dispatches to this class's override
208 // and ignore_interval is restored. ignore_interval_ms_ is already set, so a
209 // persisted value overrides the constructor default.
210 load();
212 }
213
214 private:
215 void handleInterrupt();
216
217 unsigned int ignore_interval_ms_;
218 elapsedMillis since_last_event_;
219 virtual bool to_json(JsonObject& root) override;
220 virtual bool from_json(const JsonObject& config) override;
221};
222
223const String ConfigSchema(const DigitalInputDebounceCounter& obj);
224
225bool ConfigRequiresRestart(const DigitalInputDebounceCounter& obj);
226
247class DigitalInputChange : public DigitalInput, public Sensor<bool> {
248 public:
249 DigitalInputChange(uint8_t pin, int pin_mode, int interrupt_type,
250 String config_path = "")
251 : DigitalInput{pin, pin_mode},
252 Sensor<bool>(config_path),
253 interrupt_type_{interrupt_type},
254 triggered_{true} {
255 load();
256 output_ = (bool)digitalRead(pin_);
257 last_output_ = !output_; // ensure that we always send the first output_
258
259 isr_event_ = event_loop()->onInterrupt(pin_, interrupt_type_, [this]() {
260 output_ = (bool)digitalRead(pin_);
261 triggered_ = true;
262 });
263
264 tick_event_ = event_loop()->onTick([this]() {
265 noInterrupts();
266 bool t = triggered_;
267 bool val = output_;
268 if (t && (val != last_output_)) {
269 triggered_ = false;
270 last_output_ = val;
271 interrupts();
272 notify();
273 } else {
274 interrupts();
275 }
276 });
277 }
278
280 if (tick_event_ != nullptr) {
281 tick_event_->remove(event_loop());
282 }
283 if (isr_event_ != nullptr) {
284 isr_event_->remove(event_loop().get());
285 }
286 }
287
288 private:
289 int interrupt_type_;
290 bool triggered_;
291 bool last_output_;
292 reactesp::TickEvent* tick_event_ = nullptr;
293 reactesp::ISREvent* isr_event_ = nullptr;
294 virtual bool to_json(JsonObject& doc) override { return true; }
295 virtual bool from_json(const JsonObject& config) override { return true; }
296};
297
298} // namespace sensesp
299
300#endif
DigitalInputChange provides output whenever a digital pin changes its state.
DigitalInputChange(uint8_t pin, int pin_mode, int interrupt_type, String config_path="")
DigitalInputCounter counts interrupts and reports the count every read_delay ms.
volatile unsigned int counter_
DigitalInputCounter(uint8_t pin, int pin_mode, int interrupt_type, unsigned int read_delay, String config_path, std::function< void()> interrupt_handler)
virtual bool to_json(JsonObject &root) override
reactesp::ISREvent * isr_event_
virtual bool from_json(const JsonObject &config) override
DigitalInputCounter(uint8_t pin, int pin_mode, int interrupt_type, unsigned int read_delay, String config_path="")
DigitalInputCounter(uint8_t pin, int pin_mode, int interrupt_type, unsigned int read_delay, String config_path, std::function< void()> interrupt_handler, LoadConfig load_config)
reactesp::RepeatEvent * repeat_event_
DigitalInputDebounceCounter counts interrupts and reports the count every read_delay ms,...
DigitalInputDebounceCounter(uint8_t pin, int pin_mode, int interrupt_type, unsigned int read_delay, unsigned int ignore_interval_ms, String config_path="")
DigitalInput is the base class for reading a digital GPIO pin.
DigitalInput(uint8_t pin, int pin_mode)
DigitalInputState polls the state of an input pin every read_delay ms.
DigitalInputState(uint8_t pin, int pin_mode, int read_delay=1000, String config_path="")
virtual bool load() override
Load and populate the object from a persistent storage.
Definition saveable.cpp:8
Sensor template class for any sensor producing actual values.
Definition sensor.h:42
virtual const T & get() const
void emit(const T &new_value)
const String ConfigSchema(const SmartSwitchController &obj)
std::shared_ptr< reactesp::EventLoop > event_loop()
Definition sensesp.cpp:9
bool ConfigRequiresRestart(const HTTPServer &obj)