forked from meshtastic/firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDetectionSensorModule.cpp
More file actions
164 lines (146 loc) · 7.1 KB
/
Copy pathDetectionSensorModule.cpp
File metadata and controls
164 lines (146 loc) · 7.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "DetectionSensorModule.h"
#include "Default.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "main.h"
#include <Throttle.h>
DetectionSensorModule *detectionSensorModule;
#define GPIO_POLLING_INTERVAL 100
#define DELAYED_INTERVAL 1000
typedef enum {
DetectionSensorVerdictDetected,
DetectionSensorVerdictSendState,
DetectionSensorVerdictNoop,
} DetectionSensorTriggerVerdict;
typedef DetectionSensorTriggerVerdict (*DetectionSensorTriggerHandler)(bool prev, bool current);
static DetectionSensorTriggerVerdict detection_trigger_logic_level(bool prev, bool current)
{
return current ? DetectionSensorVerdictDetected : DetectionSensorVerdictNoop;
}
static DetectionSensorTriggerVerdict detection_trigger_single_edge(bool prev, bool current)
{
return (!prev && current) ? DetectionSensorVerdictDetected : DetectionSensorVerdictNoop;
}
static DetectionSensorTriggerVerdict detection_trigger_either_edge(bool prev, bool current)
{
if (prev == current) {
return DetectionSensorVerdictNoop;
}
return current ? DetectionSensorVerdictDetected : DetectionSensorVerdictSendState;
}
const static DetectionSensorTriggerHandler handlers[_meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_MAX + 1] = {
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_LOGIC_LOW] = detection_trigger_logic_level,
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_LOGIC_HIGH] = detection_trigger_logic_level,
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_FALLING_EDGE] = detection_trigger_single_edge,
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_RISING_EDGE] = detection_trigger_single_edge,
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_EITHER_EDGE_ACTIVE_LOW] = detection_trigger_either_edge,
[meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_EITHER_EDGE_ACTIVE_HIGH] = detection_trigger_either_edge,
};
int32_t DetectionSensorModule::runOnce()
{
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
// moduleConfig.detection_sensor.enabled = true;
// moduleConfig.detection_sensor.monitor_pin = 10; // WisBlock PIR IO6
// moduleConfig.detection_sensor.monitor_pin = 21; // WisBlock RAK12013 Radar IO6
// moduleConfig.detection_sensor.minimum_broadcast_secs = 30;
// moduleConfig.detection_sensor.state_broadcast_secs = 120;
// moduleConfig.detection_sensor.detection_trigger_type =
// meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_LOGIC_HIGH;
// strcpy(moduleConfig.detection_sensor.name, "Motion");
if (moduleConfig.detection_sensor.enabled == false)
return disable();
if (firstTime) {
#ifdef DETECTION_SENSOR_EN
pinMode(DETECTION_SENSOR_EN, OUTPUT);
digitalWrite(DETECTION_SENSOR_EN, HIGH);
#endif
// This is the first time the OSThread library has called this function, so do some setup
firstTime = false;
if (moduleConfig.detection_sensor.monitor_pin > 0) {
pinMode(moduleConfig.detection_sensor.monitor_pin, moduleConfig.detection_sensor.use_pullup ? INPUT_PULLUP : INPUT);
} else {
LOG_WARN("Detection Sensor Module: Set to enabled but no monitor pin is set. Disable module");
return disable();
}
LOG_INFO("Detection Sensor Module: init");
return setStartDelay();
}
// LOG_DEBUG("Detection Sensor Module: Current pin state: %i", digitalRead(moduleConfig.detection_sensor.monitor_pin));
if (!Throttle::isWithinTimespanMs(lastSentToMesh,
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs))) {
bool isDetected = hasDetectionEvent();
DetectionSensorTriggerVerdict verdict =
handlers[moduleConfig.detection_sensor.detection_trigger_type](wasDetected, isDetected);
wasDetected = isDetected;
switch (verdict) {
case DetectionSensorVerdictDetected:
sendDetectionMessage();
return DELAYED_INTERVAL;
case DetectionSensorVerdictSendState:
sendCurrentStateMessage(isDetected);
return DELAYED_INTERVAL;
case DetectionSensorVerdictNoop:
break;
}
}
// Even if we haven't detected an event, broadcast our current state to the mesh on the scheduled interval as a sort
// of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state
// change detections.
if (moduleConfig.detection_sensor.state_broadcast_secs > 0 &&
!Throttle::isWithinTimespanMs(lastSentToMesh,
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs,
default_telemetry_broadcast_interval_secs))) {
sendCurrentStateMessage(hasDetectionEvent());
return DELAYED_INTERVAL;
}
return GPIO_POLLING_INTERVAL;
}
void DetectionSensorModule::sendDetectionMessage()
{
LOG_DEBUG("Detected event observed. Send message");
char *message = new char[40];
sprintf(message, "%s detected", moduleConfig.detection_sensor.name);
meshtastic_MeshPacket *p = allocDataPacket();
p->want_ack = false;
p->decoded.payload.size = strlen(message);
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
if (moduleConfig.detection_sensor.send_bell && p->decoded.payload.size < meshtastic_Constants_DATA_PAYLOAD_LEN) {
p->decoded.payload.bytes[p->decoded.payload.size] = 7; // Bell character
p->decoded.payload.bytes[p->decoded.payload.size + 1] = '\0'; // Bell character
p->decoded.payload.size++;
}
lastSentToMesh = millis();
if (!channels.isDefaultChannel(0)) {
LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
service->sendToMesh(p);
} else
LOG_ERROR("Message not allow on Public channel");
delete[] message;
}
void DetectionSensorModule::sendCurrentStateMessage(bool state)
{
char *message = new char[40];
sprintf(message, "%s state: %i", moduleConfig.detection_sensor.name, state);
meshtastic_MeshPacket *p = allocDataPacket();
p->want_ack = false;
p->decoded.payload.size = strlen(message);
memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size);
lastSentToMesh = millis();
if (!channels.isDefaultChannel(0)) {
LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
service->sendToMesh(p);
} else
LOG_ERROR("Message not allow on Public channel");
delete[] message;
}
bool DetectionSensorModule::hasDetectionEvent()
{
bool currentState = digitalRead(moduleConfig.detection_sensor.monitor_pin);
// LOG_DEBUG("Detection Sensor Module: Current state: %i", currentState);
return (moduleConfig.detection_sensor.detection_trigger_type & 1) ? currentState : !currentState;
}