-
Notifications
You must be signed in to change notification settings - Fork 317
/
_P151_CISA.ino
436 lines (351 loc) · 12.1 KB
/
_P151_CISA.ino
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
//#######################################################################################################
//################################ Plugin 151: CISA door lock ###########################################
//#######################################################################################################
//############################### Plugin for ESP Easy by DatuX ###############################
//################################### http://www.datux.nl ##############################################
//#######################################################################################################
//green: door will unlock as soon as person touches door
//red: door will stay locked as soon as person touches it.
//orange: you just closed the door, unlocking delay is active (otherwise it would keep unlocking)
//blinking: mechanical lock is unlocked: please close (or open+close) the door, or dont touch the door.
#include "src/Helpers/_CPlugin_Helper.h"
#ifdef PLUGIN_BUILD_TESTING
#define PLUGIN_151
#define PLUGIN_ID_151 151
#define PLUGIN_NAME_151 "Cisa door lock [TESTING]"
#ifndef CONFIG
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
#endif
bool Plugin_151_want_unlock=false;
unsigned long Plugin_151_last_unlock_time=0;
unsigned long Plugin_151_last_heartbeat_time=0;
unsigned long Plugin_151_invert_time=0; //timestamp after which to automatcily invert unlock status.
byte unlock_coil_pin=0;
#define LONG_AVERAGE_FACTOR 100
float Plugin_151_long_average_sense=0;
//sensor feedback:
// 0=mechanism is unlocked
// 1=mechanism is locked
// 2=locked, and sensing hand
int Plugin_151_last_status=-1;
//measure capicitance by pulsing out_pin and measuring response delay of in_pin
//if capicitance is too high it aborts (1000 cycles for now)
int Plugin_151_sense(byte out_pin, byte in_pin)
{
long count=0;
long max_pulses=100;
long skip_pulses=20;
pinMode(out_pin,OUTPUT);
pinMode(in_pin, INPUT);
unsigned long m;
for (long pulses=0; pulses<max_pulses ; pulses++ )
{
// m=micros();
m=0;
digitalWrite(out_pin,0);
// while (digitalRead(in_pin)!=0 && count<1000*max_pulses) count++;
while (digitalRead(in_pin)!=0 && m<1000) m++;
if (pulses>=skip_pulses)
count=count+(m);
delay(1); //let it further charge the capacitive load
// m=micros();
m=0;
digitalWrite(out_pin,1);
while (digitalRead(in_pin)!=1 && m<1000) m++;
if (pulses>=skip_pulses)
count=count+(m);
delay(1); //let it further charge the capacitive load
}
// if (count>=1000*max_pulses)
// return(-1);
return(count/ (max_pulses-skip_pulses));
}
//send unlock pulse
void Plugin_151_unlock(byte pin)
{
pinMode(pin, OUTPUT);
digitalWrite(pin,1);
delay(100);
digitalWrite(pin,0);
}
//use timer to blink pin with certain speed and dutycycle
void Plugin_151_blink(byte pin, unsigned long on_time, unsigned long total_time, bool on)
{
pinMode(pin, OUTPUT);
bool set;
if (on)
{
set=(millis()%total_time)<on_time;
}
else
{
set=(millis()%total_time)< (total_time-on_time);
}
digitalWrite(pin, set);
}
boolean Plugin_151(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_151;
Device[deviceCount].Type = DEVICE_TYPE_TRIPLE;
Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_SINGLE;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = false;
Device[deviceCount].ValueCount = 1;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = false;
Device[deviceCount].GlobalSyncOption = false;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_151);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], "LockStatus");
break;
}
case PLUGIN_WEBFORM_LOAD:
{
addFormCheckBox(F("Invert led voltage"), F("led_invert"), CONFIG(4));
addFormPinSelect(F("Sense out pin"), F("sense_out"), CONFIG(0));
addFormPinSelect(F("Sense in pin"), F("sense_in"), CONFIG(1));
addFormNumericBox(F("Sense percentage"), F("sense_percentage"), CONFIG(2), 0, 100);
addUnit(F("%"));
addFormNote(F("15% is a good starting point. Make sure door is locked when you change settings and during reboot."));
// addFormNumericBox(F("Sense hand detect minimum"), F("sense_person"), CONFIG(3), 0, 65535);
addFormNumericBox(F("Unlock delay"), F("unlock_delay"), CONFIG(5), 0, 65535);
addUnit(F("ms"));
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
CONFIG(0) = getFormItemInt(F("sense_out"));
CONFIG(1) = getFormItemInt(F("sense_in"));
CONFIG(2) = getFormItemInt(F("sense_percentage"));
// CONFIG(2) = getFormItemInt(F("sense_locked"));
// CONFIG(3) = getFormItemInt(F("sense_person"));
CONFIG(4) = isFormItemChecked(F("led_invert"));
CONFIG(5) = getFormItemInt(F("unlock_delay"));
Plugin_151_long_average_sense=0;
success = true;
break;
}
case PLUGIN_INIT:
{
success = true;
break;
}
case PLUGIN_TEN_PER_SECOND:
{
int sense=Plugin_151_sense(CONFIG(0), CONFIG(1));
int avg_sense=0;
int sense_delta=0;
//keep a long running average to account for drift
if (Plugin_151_long_average_sense)
{
avg_sense=Plugin_151_long_average_sense;
//calculate sense change percentage
if (avg_sense)
sense_delta=(sense-avg_sense)*100/avg_sense;
//only average when the sense_delta doesnt vary too much (otherwise door is open/hand is detected)
if (abs(sense_delta)<CONFIG(2))
Plugin_151_long_average_sense=(Plugin_151_long_average_sense*(LONG_AVERAGE_FACTOR-1) + sense ) / LONG_AVERAGE_FACTOR;
}
else
Plugin_151_long_average_sense=sense;
unlock_coil_pin=Settings.TaskDevicePin1[event->TaskIndex];
byte locked_led_pin=Settings.TaskDevicePin2[event->TaskIndex];
byte unlocked_led_pin=Settings.TaskDevicePin3[event->TaskIndex];
byte led_on=!CONFIG(4) ;
pinMode(locked_led_pin, OUTPUT);
pinMode(unlocked_led_pin, OUTPUT);
String log;
log=log+F("lock : ");
//activate the correct led (usually lock-led is red and unlocked led is green)
// byte active_led;
// if (Plugin_151_want_unlock)
// {
// log=log+F("UNLOCKED");
// active_led=unlocked_led_pin;
// digitalWrite(locked_led_pin,!led_on);
// }
// else
// {
// log=log+F("LOCKED");
// active_led=locked_led_pin;
// digitalWrite(unlocked_led_pin,!led_on);
// }
//automaticly invert locking status after this time (usefull to temporary unlock a door)
if (Plugin_151_invert_time)
{
if (millis()>Plugin_151_invert_time)
{
Plugin_151_want_unlock=!Plugin_151_want_unlock;
Plugin_151_invert_time=0;
}
else
{
log=log+F("(");
log=log+((Plugin_151_invert_time-millis())/1000);
log=log+F("s )");
}
}
log=log+F(" mechanism: sense=")+sense+F(" ")+F(" avg=")+avg_sense+F(" perc=")+sense_delta+F(" ");
int status=-1;
if (sense_delta<-CONFIG(2))
{
status=0; //unlocked
}
else if (sense_delta<CONFIG(2))
{
status=1; //locked
}
else
{
status=2; //locked, hand detected
}
//STATE: mechanism locked and/or person detected
if (status==1 || status==2 )
{
log=log+F("locked");
//person detected
if (status==2)
{
//allowed to unlock the door?
if (Plugin_151_want_unlock)
{
//last time we unlocked long enough?
if (millis()-Plugin_151_last_unlock_time>CONFIG(5))
{
//open the locking mechanism
log=log+F(", person detected, opening");
Plugin_151_unlock(unlock_coil_pin);
}
else
{
log=log+F(", person detected, delaying next open");
Plugin_151_blink(locked_led_pin, 500,1000, led_on);
Plugin_151_blink(unlocked_led_pin, 500,1000, led_on);
Plugin_151_last_unlock_time=millis(); //reset time until the person releases the door knob
}
}
//not allowed to open door
else
{
//last time we unlocked long enough?
if (millis()-Plugin_151_last_unlock_time>CONFIG(5))
{
//warn user the door is locked and cant be openend
log=log+F(", person detected, denied access!");
}
else
{
log=log+F(", person detected, delaying denied access.");
}
Plugin_151_blink(locked_led_pin, 500,1000, led_on);
digitalWrite(unlocked_led_pin, !led_on);
}
}
//mechanism locked, but no person detected
else
{
if (Plugin_151_want_unlock)
{
//inform user the door is unlocked
Plugin_151_blink(unlocked_led_pin, 500,1000, led_on);
digitalWrite(locked_led_pin, !led_on);
}
else if (millis()-Plugin_151_last_unlock_time<=CONFIG(5))
{
//delay is still active, inform user by making it orange.
digitalWrite(locked_led_pin, led_on);
digitalWrite(unlocked_led_pin, led_on);
}
else
{
//idle, show heartbeat (needs to be very short so cant use the blink routine)
digitalWrite(unlocked_led_pin, !led_on);
if (millis()-Plugin_151_last_heartbeat_time>3000)
{
Plugin_151_last_heartbeat_time=millis();
digitalWrite(locked_led_pin, led_on);
delay(100);
}
digitalWrite(locked_led_pin, !led_on);
}
}
}
//STATE: mechanism unlocked
else
{
if (Plugin_151_want_unlock)
{
log=log+F("unlocked");
}
else
{
log=log+F("unlocked, please close door!");
}
Plugin_151_blink(unlocked_led_pin, 500,1000, led_on);
digitalWrite(locked_led_pin, !led_on);
Plugin_151_last_unlock_time=millis();
}
addLog(LOG_LEVEL_DEBUG, log);
//send status?
if (status!=Plugin_151_last_status)
{
Plugin_151_last_status=status;
UserVar.setSensorTypeLong(event->TaskIndex, status);
sendData(event);
}
}
// case PLUGIN_GET_DEVICEGPIONAMES:
// {
//
// event->String1=F("Unlock coil pin");
// event->String2=F("Locked led pin");
// event->String3=F("Unlocked led pin");
// break;
// }
case PLUGIN_WRITE:
{
String command = parseString(string, 1);
//unlock when person touches door handle
if (command == F("cisa_unlock") || command == F("cisa_unlockhard"))
{
Plugin_151_want_unlock=true;
Plugin_151_invert_time=0;
if (event->Par1)
Plugin_151_invert_time=millis()+event->Par1*1000;
success = true;
}
//unlock now
if (command == F("cisa_unlockhard"))
{
Plugin_151_unlock(unlock_coil_pin);
success = true;
}
if (command == F("cisa_lock"))
{
Plugin_151_want_unlock=false;
Plugin_151_invert_time=0;
if (event->Par1)
Plugin_151_invert_time=millis()+event->Par1*1000;
success = true;
}
break;
}
}
return success;
}
#endif