[RELEASE] QolSys IQ Alarm Panel Drivers

Thanks. This makes sense and clears up a LOT. I am new to the Hubitat world and still learning. as an FYI, I created the rule and tried a few different options for the Parameter. It failed everytime. I assumed decimal would work as I saw BigDecimal in your code but still fails with this;

2022-04-30 09:34:14.028 am errorgroovy.lang.MissingMethodException: No signature of method: user_driver_dcaton_qolsysiqpanel_QolSys_IQ_Alarm_Panel_558.disarm() is applicable for argument types: (java.math.BigDecimal) values: [######]
Possible solutions: disarm(java.lang.String, java.math.BigDecimal), alarm(java.lang.String, java.lang.String), is(java.lang.Object), isCase(java.lang.Object) on line 5524 (method disarm)

It had my correct code where the ##### are

to add to this, the function works fine if I ARM/DISARM, etc via the device itself

Any thoughts?

Only reason I used big decimal is because it filters input to only digits if you're activating the command on the device page. I guess I should change it to a string and then check to make sure it's a valid number in the code.

It's a long shot, but could you try adding ".0" to the user code and see if it works? That might cause the parameter to be passed as a decimal. Probably won't work but worth a try. I'll try to fix the problem later on today.

@dcaton1220 I hadn't looked into the direct integration for the Qolsys panels in a long while. Last time I checked, I think HE only had the webSocket option which failed because of SSL errors. I picked it back up a few days ago to try again trying out the EventStream and rawSocket interfaces and was getting no where (I'm not a programmer but can usually brute force my way through it). I was searching an error I was getting and was pleasantly surprised to find that you've already done what I was trying to do! Thanks a million for this!

Alright. I've got the same issue. Punching the code in at the device page works flawlessly. When I pass the code via an RM rule, it throws an error. This is a throwaway code for testing, so no concern about it being exposed here.

dev:6882022-07-01 12:06:31.303 pm errorgroovy.lang.MissingMethodException: No signature of method: user_driver_dcaton_qolsysiqpanel_QolSys_IQ_Alarm_Panel_844.disarm() is applicable for argument types: (java.lang.Integer) values: [9797] Possible solutions: disarm(java.lang.String, java.math.BigDecimal), alarm(java.lang.String, java.lang.String), is(java.lang.Object), isCase(java.lang.Object) on line 5621 (method disarm)

I tried adding the '.0' to the passed parameter, but no difference.

dev:6882022-07-01 12:08:29.533 pm errorgroovy.lang.MissingMethodException: No signature of method: user_driver_dcaton_qolsysiqpanel_QolSys_IQ_Alarm_Panel_844.disarm() is applicable for argument types: (java.lang.String) values: [9797.0] Possible solutions: disarm(java.lang.String, java.math.BigDecimal), alarm(java.lang.String, java.lang.String), main(java.lang.String), logWarn(java.lang.String), is(java.lang.Object), isCase(java.lang.Object) on line 5621 (method disarm)

EDIT: So it looks like the problem with using RM is that it passes all the parameters together. Since every command has multiple fields, I don't think the driver can interpret the parameters properly. To verify, I updated the disarm function to, more or less, statically set the partition_id and running a rule with a number parameter for the user_code worked just fine.

def disarm( String partition_id = '0', BigDecimal user_code ) {
    logTrace( "disarm partition ${partition_id} usercode ${user_code}" )

    if (!user_code) {
        logError( 'Alarm panel user code not specified.  You cannot disarm the system without a user code.')
        return
    }

    if (checkAllowArming() && checkPartition(partition_id)) {
        def msg = _createArmCommand( partition_id, "DISARM", user_code);
        processEvent( "Error_Partition_${partition_id}", "(No error)" );
        sendCommand(msg);
    }
}

EDIT2: I realized you can pass more than one parameter using RM. So, I set the first parameter as a string and sent the partition_id and a second parameter as a number and sent the code. It worked! I imagine this needs to be done for each possible parameter of the command.

image

@dcaton1220 Found another issue. I do not have secure arming enabled, but was getting an error in the app when not providing the user code:

QolSys IQ Alarm Panel: Secure arming enabled for partition 0. User code must be specified in order to arm panel.

I could see in the logs, that the "Secure_Arm_Partition_0" object should have been set to 'false'.

QolSys IQ Alarm Panel: json: [event:INFO, info_type:SUMMARY, partition_list:[[partition_id:0, name:partition1, status:DISARM, secure_arm:false,

Here's where I think the problem is:

private boolean checkSecureArming(String partition_id, BigDecimal user_code = 0) {
     if (getDataValue( "Secure_Arm_Partition_${partition_id}" ) && user_code == 0) {
        logError( "Secure arming enabled for partition ${partition_id}.  User code must be specified in order to arm panel.")
        return false;
    }
    
    return true;
}

I don't think the function was working as intended. If I've got it right in my head (and there's a good chance I don't) then inside of checkSecureArming, this would have returned a string of 'false' and not an evaluated condition of 'false'. That would make the evaluated condition 'true' so the whole if condition is always true.

getDataValue( "Secure_Arm_Partition_${partition_id}" )

I think the intent was (in pseudocode)

if (secure_arm == true AND user_code == null)
    log(error)
    return true

Which brings me to the second point. From what I can tell in the rest of the code you want to check if secure arming is enabled. So, if the above conditions are met, then you'd want to return a 'true' response.

So, I updated the method to this:

private boolean checkSecureArming(String partition_id, BigDecimal user_code = 0) {
     if (getDataValue( "Secure_Arm_Partition_${partition_id}" ) == 'true' && user_code == 0) {
        logError( "Secure arming enabled for partition ${partition_id}.  User code must be specified in order to arm panel.")
        return false;
    }
    
    return true;
}

The issue now is that there's no defined message format for this. There's still a space for the user code in the sent message. I imagine the panel is looking for it to either not be there or have a placeholder like "arming_type": "ARM_STAY", "user_code":, "delay": 0

EDIT: It's looking for the field to just not be there. I moved the comma after "arming_type" to the if statement for the user code to keep it from sending the comma if no user code was provided.

private String _createArmCommand( String partition_id, String arming_type, BigDecimal user_code = 0, BigDecimal delay = 0, String bypass = "" ) {
    def command = '{ "version": 1, "source": "C4", "action": "ARMING", "nonce": "", "token": "' + accessToken + '", "partition_id":' + partition_id.toString() + '", "arming_type": "' + arming_type + '"' ;
    
    if (user_code != 0) {
        command += ', "usercode": "' + user_code.toString() + '"';
    }
    
    if (arming_type == "ARM_STAY" || arming_type == "ARM_AWAY" ) {
        command += ', "delay": ' + delay.toString() + ', "bypass": ' + (bypass == "Yes" ? "true" : "false");
    }
    
    command += '}';
    
    return command
}

Starting July 3rd, when I check the event logs in HE device manager it shows SocketReceiveError.

It's repeated every 30 seconds, I am able to arm and disarm from HE, It is connected as far as i can tell.

I rebooted both my HE and the alarm panel. The same issue is repeated every 30 seconds.

I fully removed the Alarm Panel, uninstalled the driver installation via Package Manager, and reinstalled it. I changed the access token on the panel, verified I lost connection, regenerated the token, and verified the connection. Yet the SocketReceiveError persists.

attached are screenshots of the error and error details. Any insight would be greatly appreciated.

Thanks for all this. I'm out of town at the moment and don't have access to a panel to test. I did make some updates to the code, but I didn't publish them yet because they weren't fully tested. I won't be back home until the end of July.

How many devices do you have connected to your alarm panel (not including any z-wave devices)? The alarm panel periodically transmits the status of the devices which creates a fairly steady stream of messages. If you don't have many devices connected, perhaps the socket times out. It will reconnect so there's really nothing to worry about. I'm out of town right now but I logged into my HE remotely and don't see those messages. Are you running the latest version of HE?

I'm seeing the same error under the "events" page from the device, but, I'm not seeing anything in the main logs. I'll do some poking around today to see if I can come up with anything.

EDIT: This error also just started appearing for me. Oddly, it literally just started happening about 45 minutes ago. What's weird is nothing shows in the main logs. Just these event entries. And like @user135 I'm still getting devices updates and what-not. Weird.

EDIT2: Even weirder...I'm not getting a connection failure when cURL'ing the panel directly, but I'm not getting any messages coming across either. Something appears to have changed with the panel. What's weird is that the messages are coming across to HE still. Opening a window with the curl connection open and monitoring the HE logs. I see the event in the HE logs, but nothing across the open curl connection. I did eventually get an "SSL/TLS connection timeout" error from the cURL.

I didn't think to look in the events page; I see the same timeout messages. Guess they can be ignored; my system is working fine.

The panel may only support a single connection, or it may allow multiple connections but only send info out on the first. The interface is meant for Control4 integration, it's not intended for general use and isn't documented publicly, so it's probably not as robust as it would be if it were a publicly documented API.

I currently have 6 devices connected to the panel. (All Z-Wave devices are connected to the HE hub and not the panel) so 5 total sensors + the panel Glassbreak:

I am running the latest firmware for HE. I did that upgrade while troubleshooting initially.

image

image

I know it'll support both at the same time since I used it when setting everything up. I think we might be hitting a rate limit somewhere. I all of a sudden stopped getting the device event error for about two minutes and was able to get a response to curl. Then it clamped down again, I'm seeing the socket receive error, and curl isn't getting anything back.

One last thing to add:

When all of this started, my panel would randomly be given the ALARM status and set the panel off. The logs indicate the command was sent to the panel from HE. THis happened in the middle of the night. When i disabled the 3rd party connection setting in the panel, The event triggers stopped. I have not re-enabled it, yet, but will do so now to test further.

Can't imagine how that could happen. Do you have any rules in HE that could trigger an alarm condition? I've been using these drivers for well over a year in two different houses with IQ2+ panels and haven't seen any issues at all. I don't have any personal experience with the IQ4 though.

Those device events aren't HE sending the command. That's just the panel reporting back that the alarm was triggered. You'd only know if the command was sent from HE if you have debugging enabled and are looking in the main hub logs.

What an incredible driver!! Thanks for making this. All my IQPanel sensors are now usable inside HE which is amazing!

I'm still trying to figure out how to use this driver to alert me if my alarm system is tripped. My house has the IQPanel pre installed but I'm not paying for a monitoring service. But I think with this driver, I can essentially self-monitor

Set up a rule that fires when the alarm system's Alarm_Mode_Partition_0 attribute changes to one of the "ALARM" values. All the possible values for that attribute should be listed in the readme page in the GitHub repository.

1 Like

I just have mine set to alert of any change for that attribute. Seemed like the simplest route to take.

I'm seeing strange behavior on my motion sensors. It does detect motion but reverts back to "inactive" a split second later. This is happening on both wireless motion sensors and the panel motion sensor. Including a screenshot of the logs

These aren't the logs. This is just the device events. You'll want to enable debugging from the main panel device, recreate the event, and post a snippet from the main logging page. Like below. You'll want to select your panel device at the top of the log page to filter the logs.