269
269
<synopsis>Disarm delay</synopsis>
270
270
<description>
271
271
<para>Number of seconds grace period permitted to disarm an active alarm after this sensor triggers before considering it a breach.</para>
272
+ <para>If set to 0, activation of this sensor will never trigger an alarm. This can be useful for certain sensors, like window sensors on windows that are not a breach threat. Events will still be generated for these sensors, allowing automation actions to be taken if desired.</para>
273
+ <para>Consequently, to have a sensor that always triggers a breach alarm immediately, set this option to 1 second.</para>
272
274
</description>
273
275
</configOption>
274
276
</configObject>
389
391
<ref type="application">AlarmReceiver</ref>
390
392
</see-also>
391
393
</application>
394
+ <function name="ALARMSYSTEM_SENSOR_TRIGGERED" language="en_US">
395
+ <synopsis>
396
+ Returns whether an alarm sensor is currently triggered
397
+ </synopsis>
398
+ <syntax>
399
+ <parameter name="client" required="true">
400
+ <para>Client name as configured in <literal>res_alarmsystem.conf</literal></para>
401
+ </parameter>
402
+ <parameter name="sensor" required="true">
403
+ <para>Sensor name as configured in <literal>res_alarmsystem.conf</literal></para>
404
+ </parameter>
405
+ </syntax>
406
+ <description>
407
+ <para>Returns whether an alarm system sensor is currently triggered.</para>
408
+ </description>
409
+ </function>
392
410
***/
393
411
394
412
#define MODULE_NAME "res_alarmsystem"
@@ -538,7 +556,6 @@ struct alarm_client {
538
556
enum alarm_state state ; /* Internal aggregate alarm state */
539
557
unsigned int ip_connected :1 ; /* IP connectivity good or lost? */
540
558
pthread_t thread ;
541
- ast_mutex_t lock ; /*! \todo not used, remove */
542
559
int alertpipe [2 ];
543
560
char client_id [AST_MAX_EXTENSION ];
544
561
char client_pin [AST_MAX_EXTENSION ];
@@ -552,6 +569,7 @@ struct alarm_client {
552
569
time_t autoservice_start ;
553
570
time_t breach_time ;
554
571
time_t last_arm ;
572
+ time_t ip_lost_time ; /* Time that IP connectivity was last lost */
555
573
int egress_delay ;
556
574
char * contexts [NUM_ALARM_EVENTS ];
557
575
struct alarm_sensors sensors ;
@@ -681,7 +699,6 @@ static void cleanup_client(struct alarm_client *c)
681
699
ast_free (c -> cid_name );
682
700
}
683
701
ast_alertpipe_close (c -> alertpipe );
684
- ast_mutex_destroy (& c -> lock );
685
702
ast_free (c );
686
703
}
687
704
@@ -1250,9 +1267,19 @@ static int generate_event(struct alarm_client *c, enum alarm_event_type event, s
1250
1267
static void set_ip_connected (struct alarm_client * c , int connected )
1251
1268
{
1252
1269
if (connected != c -> ip_connected ) {
1270
+ time_t now ;
1253
1271
ast_log (LOG_NOTICE , "Client '%s' is now %s\n" , c -> name , connected ? "ONLINE" : "OFFLINE" );
1254
1272
c -> ip_connected = connected ;
1255
1273
generate_event (c , connected ? EVENT_INTERNET_RESTORED : EVENT_INTERNET_LOST , NULL , NULL );
1274
+ now = time (NULL );
1275
+ if (connected ) {
1276
+ if (c -> ip_lost_time >= now - 1 ) {
1277
+ /* Possible, and likely just highly coincidental. */
1278
+ ast_debug (1 , "Interesting! IP connectivity restored immediately after it was lost!\n" );
1279
+ }
1280
+ } else {
1281
+ c -> ip_lost_time = now ;
1282
+ }
1256
1283
}
1257
1284
}
1258
1285
@@ -1710,14 +1737,30 @@ static void *client_thread(void *arg)
1710
1737
* if we get stuck in the POLLERR case above.
1711
1738
* This ensure that this will always get executed periodically,
1712
1739
* such as to report events by phone if needed. */
1713
- if (res == 0 || ( c -> ip_connected == 0 ) ) { /* res == 0 */
1740
+ if (res == 0 || c -> ip_connected == 0 ) { /* res == 0 */
1714
1741
time_t now = time (NULL );
1715
1742
/* No need for pings if IP isn't enabled */
1716
- if (now >= c -> last_ip_ack + c -> ping_interval * 2 + 1 ) {
1717
- /* Haven't gotten any ACKs over IP from the server in a while.
1718
- * Set client as offline. */
1719
- ast_debug (1 , "Time is %lu, but haven't gotten an ACK since %lu\n" , now , c -> last_ip_ack );
1720
- set_ip_connected (c , 0 );
1743
+ if (c -> ip_connected ) {
1744
+ /* Handling to determine if we think the client is still online when it's really offline now */
1745
+ if (now >= c -> last_ip_ack + c -> ping_interval * 3 + 1 ) {
1746
+ /* Haven't gotten any ACKs over IP from the server in a while.
1747
+ * Set client as offline. */
1748
+ ast_debug (1 , "Confirmed connectivity loss: time is %lu, but haven't gotten an ACK since %lu\n" , now , c -> last_ip_ack );
1749
+ set_ip_connected (c , 0 );
1750
+ /* It is possible at this point that we will get a reply to the next ping we send,
1751
+ * later on in this function. The bizarre effect of this is that it is possible
1752
+ * to have an INTERNET_LOST event immediately followed by INTERNET_RESTORED.
1753
+ * It would require just the right number of pings to be lost followed by one that is not,
1754
+ * immediately after we determine that connectivity has been lost. */
1755
+ } else if (now >= c -> last_ip_ack + c -> ping_interval * 2 + 1 ) {
1756
+ /* Haven't gotten any ACKs over IP from the server in a while.
1757
+ * Don't immediately mark client as offline though. */
1758
+ ast_debug (1 , "Likely connectivity loss: time is %lu, but haven't gotten an ACK since %lu\n" , now , c -> last_ip_ack );
1759
+ ast_log (LOG_NOTICE , "Significant packet loss encountered, possible connectivity loss\n" );
1760
+ /* Don't set connected to 0 yet... allow one more ping, and send an extra one just to be sure. */
1761
+ generate_event (c , EVENT_PING , NULL , NULL );
1762
+ usleep (50000 ); /* Wait briefly before sending the next packet, since if this one is dropped, the next one probably will be too */
1763
+ }
1721
1764
}
1722
1765
/* There might still be some outstanding events that need to be delivered.
1723
1766
* For example, a few seconds ago, we were woken up to send events to server by IP,
@@ -1899,7 +1942,6 @@ static int load_config(void)
1899
1942
}
1900
1943
strcpy (c -> data , cat ); /* Safe */
1901
1944
c -> name = c -> data ;
1902
- ast_mutex_init (& c -> lock );
1903
1945
c -> alertpipe [0 ] = c -> alertpipe [1 ] = -1 ;
1904
1946
if (ast_alertpipe_init (c -> alertpipe )) {
1905
1947
ast_log (LOG_ERROR , "Failed to initialize alertpipe\n" );
@@ -2209,6 +2251,7 @@ static int alarmsensor_exec(struct ast_channel *chan, const char *data)
2209
2251
2210
2252
/* Okay, now we can start.
2211
2253
* Since the sensor just took the sensor loop off hook, it has been triggered. */
2254
+ s -> triggered = 1 ;
2212
2255
2213
2256
/* Update state from OK to TRIGGERED.
2214
2257
* From here, it can return to ALARM_STATE_OK if disarmed within s->disarm_delay time.
@@ -2217,6 +2260,9 @@ static int alarmsensor_exec(struct ast_channel *chan, const char *data)
2217
2260
if (is_egress ) {
2218
2261
ast_debug (1 , "Egress is currently permitted, not triggering alarm\n" );
2219
2262
breach_time = 0 ;
2263
+ } else if (!s -> disarm_delay ) {
2264
+ ast_debug (1 , "Sensor does not trigger alarms, no breach timer required\n" );
2265
+ breach_time = 0 ;
2220
2266
} else {
2221
2267
time_t now = time (NULL );
2222
2268
c -> state = ALARM_STATE_TRIGGERED ;
@@ -2243,14 +2289,15 @@ static int alarmsensor_exec(struct ast_channel *chan, const char *data)
2243
2289
}
2244
2290
2245
2291
/* If we have a keypad device to autodial, kick that off */
2246
- if (!is_egress && !ast_strlen_zero (c -> keypad_device )) {
2292
+ if (breach_time && !is_egress && !ast_strlen_zero (c -> keypad_device )) {
2247
2293
orig_app_device (c -> keypad_device , NULL , "AlarmKeypad" , c -> name , c -> cid_num , c -> cid_name );
2248
2294
}
2249
2295
2250
2296
/* Now, wait for the sensor to be restored. This could be soon, it could not be. */
2251
- while (ast_safe_sleep (chan , 500 ) != -1 );
2297
+ while (ast_safe_sleep (chan , 60000 ) != -1 );
2252
2298
2253
2299
ast_debug (3 , "Sensor '%s' appears to have been restored\n" , s -> name );
2300
+ s -> triggered = 0 ;
2254
2301
generate_event (c , EVENT_ALARM_SENSOR_RESTORED , s , NULL );
2255
2302
2256
2303
/* The only time we get a WRLOCK on clients is when cleaning them up at module unload.
@@ -2469,6 +2516,59 @@ static int alarmkeypad_exec(struct ast_channel *chan, const char *data)
2469
2516
return 0 ;
2470
2517
}
2471
2518
2519
+ static int sensor_triggered_read (struct ast_channel * chan , const char * cmd , char * parse , char * buffer , size_t buflen )
2520
+ {
2521
+ char * argcopy ;
2522
+ struct alarm_client * c ;
2523
+ struct alarm_sensor * s ;
2524
+ AST_DECLARE_APP_ARGS (args ,
2525
+ AST_APP_ARG (client );
2526
+ AST_APP_ARG (sensor );
2527
+ );
2528
+
2529
+ if (ast_strlen_zero (parse )) {
2530
+ ast_log (LOG_ERROR , "Must specify client-name,sensor-name\n" );
2531
+ return -1 ;
2532
+ }
2533
+
2534
+ argcopy = ast_strdupa (parse );
2535
+ AST_STANDARD_APP_ARGS (args , argcopy );
2536
+
2537
+ if (ast_strlen_zero (args .client )) {
2538
+ ast_log (LOG_ERROR , "Must specify client name\n" );
2539
+ return -1 ;
2540
+ }
2541
+
2542
+ AST_RWLIST_RDLOCK (& clients );
2543
+ c = find_client_locked (args .client );
2544
+ if (!c ) {
2545
+ ast_log (LOG_ERROR , "Client '%s' not found in configuration\n" , args .client );
2546
+ AST_RWLIST_UNLOCK (& clients );
2547
+ return -1 ;
2548
+ }
2549
+ if (!ast_strlen_zero (args .sensor )) {
2550
+ s = find_sensor (c , args .sensor );
2551
+ if (!s ) {
2552
+ AST_RWLIST_UNLOCK (& clients );
2553
+ ast_log (LOG_ERROR , "No such sensor '%s'\n" , args .sensor );
2554
+ return -1 ;
2555
+ }
2556
+ } else {
2557
+ AST_RWLIST_UNLOCK (& clients );
2558
+ ast_log (LOG_ERROR , "Must specify sensor name\n" );
2559
+ return -1 ;
2560
+ }
2561
+
2562
+ ast_copy_string (buffer , s -> triggered ? "1" : "0" , buflen );
2563
+ AST_RWLIST_UNLOCK (& clients );
2564
+ return 0 ;
2565
+ }
2566
+
2567
+ static struct ast_custom_function acf_sensortriggered = {
2568
+ .name = "ALARMSYSTEM_SENSOR_TRIGGERED" ,
2569
+ .read = sensor_triggered_read ,
2570
+ };
2571
+
2472
2572
static char * handle_show_sensors (struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2473
2573
{
2474
2574
#define FORMAT "%-12s %-20s %s\n"
@@ -2625,6 +2725,7 @@ static int unload_module(void)
2625
2725
module_shutting_down = 1 ;
2626
2726
2627
2727
ast_cli_unregister_multiple (alarmsystem_cli , ARRAY_LEN (alarmsystem_cli ));
2728
+ ast_custom_function_unregister (& acf_sensortriggered );
2628
2729
ast_unregister_application ("AlarmSensor" );
2629
2730
ast_unregister_application ("AlarmEventReceiver" );
2630
2731
ast_unregister_application ("AlarmKeypad" );
@@ -2678,6 +2779,7 @@ static int load_module(void)
2678
2779
return AST_MODULE_LOAD_DECLINE ;
2679
2780
}
2680
2781
2782
+ ast_custom_function_register (& acf_sensortriggered );
2681
2783
ast_cli_register_multiple (alarmsystem_cli , ARRAY_LEN (alarmsystem_cli ));
2682
2784
return 0 ;
2683
2785
}
0 commit comments