DSC Alarm integration

I upddated to 30.2 this morning. Exit delay and entry delay are looking good!

UPDATED: I’d posted that the last_changed wasn’t working. I hadn’t let a full exit delay complete! Looks to be working - I’m seeing last_changed_by_user now. I’ll give it some extra testing this morning.

Also - if you want to fix it while you’re committing code, there are 3 tabs on an empty line at line 124 (in the file I have). Between handle_command_response_error and handle_poll_response.

I noticed that alarm_control_panel.home_alarm has a changed_by attribute that’s null for me.

Does that mean that the alarm component has an attribute where last_changed_by_user should be presented?

EDIT: home_alarm is created by my partition 1 “Home Alarm”

I’m only seeing a change in last_changed_by_user when the alarm is disarmed, not when it’s armed.
On a fresh restart of HA, if I arm the alarm, there’s no last_changed_by_user attribute until I disarm. In fact, if I arm the alarm and then key in a code during the exit delay, I don’t see a last_changed_by_user until I’ve gone through a full arm / disarm cycle.

This could be an issue with how I pasted-in the code you posted. I’ve got:

def handle_partition_state_change(self, code, data):
    """Handle when the envisalink sends us a partition change."""
    """Event 650-674, 652 is an exception, because 2 bytes are passed for partition and zone type."""
    if code == '652':
        parse = re.match('^[0-9]{2}$', data)
        if parse:
            partitionNumber = int(data[0])
            self._alarmPanel.alarm_state['partition'][partitionNumber]['status'].update(evl_ArmModes[data[1]]['status'])
            _LOGGER.debug(str.format("(partition {0}) state has updated: {1}", partitionNumber, json.dumps(evl_ArmModes[data[1]]['status'])))
            return partitionNumber
        else:
            _LOGGER.error("Invalid data has been passed when arming the alarm.") 
    else:
        parse = re.match('^[0-9]+$', data)
        if parse:
            partitionNumber = int(data[0])
            self._alarmPanel.alarm_state['partition'][partitionNumber]['status'].update(evl_ResponseTypes[code]['status'])
            _LOGGER.debug(str.format("(partition {0}) state has updated: {1}", partitionNumber, json.dumps(evl_ResponseTypes[code]['status'])))
            
            if code in ['700','750']:
                lastChangedByUser = {'last_changed_by_user': int(data[1:5])}
                self._alarmPanel.alarm_state['partition'][partitionNumber]['status'].update(lastChangedByUser)

            return partitionNumber
        else:
            _LOGGER.error("Invalid data has been passed in the parition update.")

For anyone that’s interested, here’s an automation that’ll notify you when someone disarms the alarm, with their name.

- alias: Alarm Disarmed
  trigger: 
    - platform: state
      entity_id: sensor.home_alarm_keypad
      state: 'Disarmed'
  condition: 
    condition: numeric_state
    entity_id:  sensor.home_alarm_keypad
    value_template: '{{ state.attributes.last_changed_by_user }}'
    above: 1
    # filter myself out
  action:
    - service: notify.notify
      data: 
        title: "Alarm"
        data:
          priority: 0
      data_template:
        message: >
          {% if states.sensor.home_alarm_keypad.attributes.last_changed_by_user %}{{ ["Scott","Wife","Son","Daughter"][states.sensor.home_alarm_keypad.attributes.last_changed_by_user - 1] }}{% else %}Someone{% endif %} disarmed the alarm

Nice thanks for testing!
Yeah spotted a few issues with tabs thanks to GitHub text editor will get those sorted!
We’ve now split it into last_armed_by_user and last_disarmed_by_user in case gives some more flexibility.
You won’t see the arming event unless you add 700 into the dsc defs file but the full updated code is nearly ready
Re last tripped time I still can’t see where that is inserted in the code but will have another look

Point me to some code if you want me to give it a run.

Thanks for working on this. I’m psyched that I was able to move all of my alarm code over to HA today. Just about done with the old Vera!

This looks like some nice functionality. I’ll try to test it at some point soon. A bit loathed to screw around with my set up at the moment as I’ve got it working well thanks to Cinntax.

Great stuff! I’ve just accepted jnimmo’s pull request for pyenvisalink. Are we ready for a release then? If so, i’ll release pyenvisalink 1.8, and you’ll have to update in your hass commit.

Yes that’s correct- it’s number of seconds, but hte envisalink device does “time out” after a given period of time, so it doesn’t go on forever.

@Cinntax: alarm_control_panel/envisalink.py needed a couple of fixes: https://github.com/srirams/home-assistant/commit/2f8deb70cb5f3621a69b6b9acb72f8e29123650c (DSC doesn’t need a code to arm, so I’ve left it as is, but you may need to change it for Honeywell. Also, if you do use a code to arm a DSC system it arms in a different mode I think…)

Great work!

@sriram I’ve got a pull request open at the moment, do you want me to see if I can integrate those changes?
It is up to how the DSC alarm is setup whether a code is required though isn’t it - I think that is a programmable option whether it can be armed without a code?

@jnimmo: that’d be great. For the code, according to the envisalink api, to arm with code is command 033 (stay arm is 031 and away arm is 030, both require no code). And when you use command 033:

[quote]The TPI will attempt to arm the selected partition by using a User Code.
This is equivalent to entering a User Code while the partition is in the
Ready mode[/quote]

So, it’s equivalent to you pushing the code at the keypad. On my system, if you do this and open the door it will arm in away mode and if you don’t open the door it will arm in stay mode.

For home automation purposes, I don’t think using command 033 is a good idea as the results are not defined (arm away or arm stay). In any case, I don’t believe pyenvisalink implements command 033, so the whatever code is sent would be ignored, I believe.

The only time a code is required is to disarm, and for that we can use the code from the configuration and return None for code_format which tells the frontend not to ask for a code.

The above only applies to DSC systems. I have no idea about Honeywell.

I can confirm that DSC alarms can be setup to require a code to arm via the programming options. I had issues with this and PyEnvisalink until I disabled the DSC requiring a code to arm and then everything worked much more smoothly.

code_format shouldn’t be returning the code anyway, meant to return a regex for the string format, i.e. 4 digits
However, if we change that to none and someone doesn’t have the code in the configuration (like me) then they can’t disarm the alarm

We could use code_format to say no code required if the code is found in the config, otherwise return the regex?

def code_format(self):
“”“Regex for code format or None if no code is required.”“”
“”“If code is specified in config, don’t prompt for it”“”
if self._code:
return None
else:
return ‘^\d{4,6}$’

While we’re on the topic; I don’t understand why the alarm_arm_home/alarm_arm_away etc methods are checking for self._code, then sending code? Anyone enlighten me? Only just noticed

Should it instead be saying if _code (specified in config) use that, otherwise use code - or doesn’t it matter

I implemented this last night and had a quick question: when an ‘opening’ zone is opened on my DSC alarm it only shows open for about 5 seconds, then reverts to closed. In the bar graph it shows off except for briefly when the state changed, where it shows on. This is helpful for automating (when window first opened take snapshot from camera), but I’m looking for a dashboard that shows what zones are open as well for monitoring when it if the house.

Is this the intended behavior?

And just to add, it looks like the “last tripped time” goes from 1-10 to 327680 when the zone is marked as off. I’m looking through the code to see if there’s an obvious reason for that.

Hi @The_Dude_Himself yeah the seconds counting up is behavior from the Envisalink panel or from the alarm itself I assume.
I was going to modify it to store the actual time last tripped but then Home Assistant has parameters to get when the state last changed anyway

The binary sensors replicate the lights shown on your alarm panel, so yes I think it is expected what you describe above

It’s been a crazy week- I have a few comments-

  1. the pyenvisalink library does now support passing the code for arm- at first it didn’t, but now it does respond with the code when challenged by the envisalink.

  2. I was returning the code there so that you were forced to enter the correct code in the UI prior to pressing the disarm button- I only got a quick sense of the issue, but it sounds like we have a conflict if you don’t have a code. Perhaps we can maybe check for existence of the configured code, and return appropriately in the format method?

  3. on the Honeywell side, I do need the code in all situations, so ill still want to pass that.

  4. there was a question about the times… Those values are actually internal envisalink timers that the Pyenvisalink library requests on an interval.

So, I’m not sure why but some Zones track better than others. They’re all wireless - that could be part of it. I’m also querying a java server (https://sites.google.com/site/mppsuite/downloads/dscserver-2), but that mimics the physical Eyez-On device. I’ll have to shut it off and point at the actual alarm once to see how it responds.

On my DSC alarm panel, if I leave a Window open, it does show as open as long as the window is open.

This is the same thing that reflects in HASS as well. At least, I don’t see it reverting to closed when the actual sensor is still open.

What does the panel show for you when the zone is open ?