269269 <synopsis>Disarm delay</synopsis>
270270 <description>
271271 <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>
272274 </description>
273275 </configOption>
274276 </configObject>
389391 <ref type="application">AlarmReceiver</ref>
390392 </see-also>
391393 </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>
392410 ***/
393411
394412#define MODULE_NAME "res_alarmsystem"
@@ -538,7 +556,6 @@ struct alarm_client {
538556 enum alarm_state state ; /* Internal aggregate alarm state */
539557 unsigned int ip_connected :1 ; /* IP connectivity good or lost? */
540558 pthread_t thread ;
541- ast_mutex_t lock ; /*! \todo not used, remove */
542559 int alertpipe [2 ];
543560 char client_id [AST_MAX_EXTENSION ];
544561 char client_pin [AST_MAX_EXTENSION ];
@@ -552,6 +569,7 @@ struct alarm_client {
552569 time_t autoservice_start ;
553570 time_t breach_time ;
554571 time_t last_arm ;
572+ time_t ip_lost_time ; /* Time that IP connectivity was last lost */
555573 int egress_delay ;
556574 char * contexts [NUM_ALARM_EVENTS ];
557575 struct alarm_sensors sensors ;
@@ -681,7 +699,6 @@ static void cleanup_client(struct alarm_client *c)
681699 ast_free (c -> cid_name );
682700 }
683701 ast_alertpipe_close (c -> alertpipe );
684- ast_mutex_destroy (& c -> lock );
685702 ast_free (c );
686703}
687704
@@ -1250,9 +1267,19 @@ static int generate_event(struct alarm_client *c, enum alarm_event_type event, s
12501267static void set_ip_connected (struct alarm_client * c , int connected )
12511268{
12521269 if (connected != c -> ip_connected ) {
1270+ time_t now ;
12531271 ast_log (LOG_NOTICE , "Client '%s' is now %s\n" , c -> name , connected ? "ONLINE" : "OFFLINE" );
12541272 c -> ip_connected = connected ;
12551273 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+ }
12561283 }
12571284}
12581285
@@ -1710,14 +1737,30 @@ static void *client_thread(void *arg)
17101737 * if we get stuck in the POLLERR case above.
17111738 * This ensure that this will always get executed periodically,
17121739 * 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 */
17141741 time_t now = time (NULL );
17151742 /* 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+ }
17211764 }
17221765 /* There might still be some outstanding events that need to be delivered.
17231766 * 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)
18991942 }
19001943 strcpy (c -> data , cat ); /* Safe */
19011944 c -> name = c -> data ;
1902- ast_mutex_init (& c -> lock );
19031945 c -> alertpipe [0 ] = c -> alertpipe [1 ] = -1 ;
19041946 if (ast_alertpipe_init (c -> alertpipe )) {
19051947 ast_log (LOG_ERROR , "Failed to initialize alertpipe\n" );
@@ -2209,6 +2251,7 @@ static int alarmsensor_exec(struct ast_channel *chan, const char *data)
22092251
22102252 /* Okay, now we can start.
22112253 * Since the sensor just took the sensor loop off hook, it has been triggered. */
2254+ s -> triggered = 1 ;
22122255
22132256 /* Update state from OK to TRIGGERED.
22142257 * 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)
22172260 if (is_egress ) {
22182261 ast_debug (1 , "Egress is currently permitted, not triggering alarm\n" );
22192262 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 ;
22202266 } else {
22212267 time_t now = time (NULL );
22222268 c -> state = ALARM_STATE_TRIGGERED ;
@@ -2243,14 +2289,15 @@ static int alarmsensor_exec(struct ast_channel *chan, const char *data)
22432289 }
22442290
22452291 /* 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 )) {
22472293 orig_app_device (c -> keypad_device , NULL , "AlarmKeypad" , c -> name , c -> cid_num , c -> cid_name );
22482294 }
22492295
22502296 /* 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 );
22522298
22532299 ast_debug (3 , "Sensor '%s' appears to have been restored\n" , s -> name );
2300+ s -> triggered = 0 ;
22542301 generate_event (c , EVENT_ALARM_SENSOR_RESTORED , s , NULL );
22552302
22562303 /* 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)
24692516 return 0 ;
24702517}
24712518
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+
24722572static char * handle_show_sensors (struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
24732573{
24742574#define FORMAT "%-12s %-20s %s\n"
@@ -2625,6 +2725,7 @@ static int unload_module(void)
26252725 module_shutting_down = 1 ;
26262726
26272727 ast_cli_unregister_multiple (alarmsystem_cli , ARRAY_LEN (alarmsystem_cli ));
2728+ ast_custom_function_unregister (& acf_sensortriggered );
26282729 ast_unregister_application ("AlarmSensor" );
26292730 ast_unregister_application ("AlarmEventReceiver" );
26302731 ast_unregister_application ("AlarmKeypad" );
@@ -2678,6 +2779,7 @@ static int load_module(void)
26782779 return AST_MODULE_LOAD_DECLINE ;
26792780 }
26802781
2782+ ast_custom_function_register (& acf_sensortriggered );
26812783 ast_cli_register_multiple (alarmsystem_cli , ARRAY_LEN (alarmsystem_cli ));
26822784 return 0 ;
26832785}
0 commit comments