Ademco/Honeywell/Vista ESPHome custom component with an esp32/esp8266

See function onDisplay in vista.cpp for the decoding of the f7 cmd. Target address is determined by bit position not as an actual readable address.

Thank you @Dilbert66 and @howardchen3 and everyone else for making this project! This is so much better than using the TotalConnect 2.0 / Residio integration and service. It’s a lot faster and more reliable.

Some notes, for anyone else who is going to try this - I have a Vista 20P and ended up ordering the printed circuit boards designed by @howardchen3 and made by JLCPCB. I made a mistake and did not realize that I was not ordering my initial boards correctly - they did not come with any of the components pre-soldered. So I had to throw my first batch of 5 away and start over again.

If you’re not familiar with how JLCPCB works, you should watch one of the many videos on Youtube which explain in more detail how it works. I watched this one and it helped me figure out what I did wrong: https://www.youtube.com/watch?v=MICBFN2mD6Q

The main thing is you need to follow the link @howardchen3 provided, create logins for JLCPCB, and download 3 files to your computer -

  1. The BOM (Build of Materials) CSV file
  2. The Gerber PCB ZIP file
  3. The Pick and Place PCB CSV file

Once you have all 3 files, you need to go to the jlcpcb.com homepage and find the section that says “PCB Assembly” and click the “Quote Now” button. For some reason I could not find that inside the web-based PCB editor tool. If you follow along with the YouTube video is mostly looks correct, but it appears JLCPCB keeps changing their website so there are some small differences.

Once you are all done, you will find that the total comes out to $40.82 for 5 circuit boards soldered with resisters, optocouplers, and the 4 wire screw terminals all attached, plus shipping to the US. If you find that the price of is something closer to $13 plus shipping, you made the same mistake I did and you’ll end up with just circuit boards and nothing soldered to them. The other hint you’re doing things correctly is there will be a proof picture after you upload the Pick and Place file - it will show a rough approximation of where the components will be soldered. If you don’t see this picture, you probably did something wrong.

Once the boards arrive, you should only have to solder the ESP8266 module. I ended up buying this one from Amazon: Sorry! Something went wrong! - it contains 5 boards with the standoffs to mount it for $15.

You do not have to solder the Mini360 voltage regulator - you power the ESP8266 with a micro-USB cord and standard USB power supply. My understanding is this is only needed if you want to attempt to have the Vista alarm board supply the power to the ESP8266. I already have too many things wired to my panel so I thought this was not going to work for me. Plus, it’s one less thing I need to worry about soldering, or adjusting, since the Mini360 has a rotatable screw knob on that must be used to adjust the voltage with a multi-meter.

What’s not clear to me is if you really need to wire up the red and black wires - if the device is being powered by the USB power supply, shouldn’t it only need the green and yellow wires to do data communication? In any case, I ended up wiring up all 4 wires since I was in the alarm panel box.
EDIT: I have now found out that if you power the ESP by the USB power supply, you do not need to wire up the red wire at all. The only 3 wires needed are the black, green and yellow wires. This means you can skip the Mini360 completely. I’ve been running mine for several months now and it works great this way.

1 Like

I also found a solution to the issue of sensor.vistaalarm_system_status sometimes showing a state of “unknown” when the system is disarmed and some sensor is not in a ready to arm state, like a motion sensor. It also doesn’t switch from disarmed to armed_away while the countdown is happening to let you leave the building; I wanted something that showed that things were in fact set to armed_away immediately.

I created a helper which reliably switched from “disarmed”, “armed_away”, “armed_stay” which could be used for things like notifications and changing my thermostat settings:

This is the input_select helper I created:

     {
        "id": "alarm_simple_status",
        "name": "Alarm Simple Status",
        "icon": "mdi:alarm-panel",
        "options": [
          "disarmed",
          "armed_away",
          "armed_stay"
        ]
      }

And this is an automation which updates the helper:

alias: Alarm Simple Status Updater
description: set Alarm Simple Status Helper to current alarm state
trigger:
  - platform: state
    entity_id:
      - sensor.vistaalarm_system_status
    to: disarmed
    id: triggerdisarmed
  - platform: state
    entity_id:
      - sensor.vistaalarm_system_status
    to: armed_home
    id: triggerarmedstay
  - platform: state
    entity_id:
      - sensor.vistaalarm_line1
    to: ARMED ***STAY***
    id: triggerarmedstay
  - platform: state
    entity_id:
      - sensor.vistaalarm_system_status
    to: armed_away
    id: triggerarmedaway
  - platform: state
    entity_id:
      - sensor.vistaalarm_line1
    to: ARMED ***AWAY***
    id: triggerarmedaway
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id:
              - triggerarmedstay
        sequence:
          - service: input_select.select_option
            data:
              option: armed_stay
            target:
              entity_id: input_select.alarm_simple_status
      - conditions:
          - condition: trigger
            id:
              - triggerarmedaway
        sequence:
          - service: input_select.select_option
            data:
              option: armed_away
            target:
              entity_id: input_select.alarm_simple_status
      - conditions:
          - condition: trigger
            id:
              - triggerdisarmed
        sequence:
          - service: input_select.select_option
            data:
              option: disarmed
            target:
              entity_id: input_select.alarm_simple_status
mode: single

Although the automation may run several times as vistaalarm_system_status switches between Unknown and Disarmed, the input_select.alarm_simple_status helper will not have its value shown as changed. This makes it convenient to use as a trigger for other automations:

trigger:
  - platform: state
    entity_id:
      - input_select.alarm_simple_status
    to: disarmed

Hopefully this helps someone else!

My setup is still working, but I do have a question - I’ve noticed the following showing up in my logs quite frequently. I’m not sure if it’s hurting anything, but I am curious if it means I’ve got something configured incorrectly:

[11:53:22][W][component:204]: Component <unknown> took a long time for an operation (0.12 s).
[11:53:22][W][component:205]: Components should block for at most 20-30ms.

EDIT: It appears to be related to this issue, which popped up recently:

Thanks @Dilbert66 and others for all your hard work and creativity to get this working. I was able to get the breadboard version working finally.

I am trying to use the HA Lovelace Custom Alarm Panel card - it looks like the Polymer library is deprecated, is there anyway to make this work?

Are there other Panel Cards others are using?

I was running the version that was on “master”. However, I found that the Custom Alarm Panel Card didn’t work for me either. I ended up downloading the “dev” version and using the alarm panel code there; it seems to be compatible if you just drop in place without changing anything else.

Yes, I will back port the dev branch version to master when I get a chance.

If anyone is interested I’ve added a new component called “web_keypad” based on the web_server component. It provides a virtual keypad for each partition of your alarm system via a web page. The page also provides all sensor statuses, ota uploads as usual. You can configure all buttons and keys using a config file. I’ve provided an example yaml file in my components directory. Just configure the yaml as usual for your system. There is an added section called web_keypad: for this new feature. The yaml is available here: GitHub - Dilbert66/esphome-components at keypad
You don’t need to configure anything by default. Just add the section as is also insuring that “web_keypad” is also listed in the external_components section above. All code and config files will be retrieved automatically from my repository and compiled in. You can modify the files to your liking after if needed.
What this accomplishes, is that you can now run this esphome component as a standalone system to provide a virtual keypad and monitor your panel without home assistant. You can disable the api and mqtt section if you want. You can also enable mqtt and use it with a non home assistant infrastructure and still have a virtual keypad. As usual, this program is still in development so bugs most likely still lurk around. I intend to add some end to end encryption (browser to esp) at some point. This is the same component as used on my DSC alarm custom component.

Note: I should add that this is only recommended for ESP32 platforms. The ESP8266 is too limited in available ram.

Note: If you find that your system is restarting and your log is very busy. add the “log: false” option to the web_keypad: section. If there is too much traffic going out, the esp gets overwhelmed. This will disable the web display of the log window.

1 Like

I’m loving this project but could use some help.

Reading data has been working great, but today I hooked up an optoisolator to be able to send keypresses from HA. It didn’t work out of the box but then I learned I need to set this up as a secondary panel (e.g. using programming code *190 with keypadaddr1: 17).

It seems my installer code is not the default (and I don’t know what it is), so I used the method of hitting # + * within 50s of a power cycle to enter programming mode. Then I hit *190 10 to try to enable the second panel at address 17 on partition 1, with no sound limitiations. Then I hit *99 to try to exit programming mode. I may have pushed a few other buttons trying to get the keypad to do anything. Here’s a snippet from the reference I found for programming Keypad 2.

But here’s where it gets weird, at this point, my main panel stopped responding altogether. So I power-cycled the whole system, and the display is still blank.

Also, my HA instance no longer reads the status lines (though I can still see them in the logs). I’ve noticed the ‘keypad address masks’ (bytes 1,2,3,4) have changed for the status message. Before they were like:

F7 20 00 03 10 08 00 1C 28 02 00 00 20 

And now they’re

F7 60 00 01 10 08 00 0C 2C 02 00 00 41 

So it would seem I somehow changed this mask in a way that my system is no longer using my primary keypad, and my HA instance is no longer paying attention to the status. Did I somehow change the whole partition of my system? If I change my esphome config to have keypadaddr1: 16 I’m able to arm/disarm the system at least, so at least I can confirm writing is working!

I’m investigating this too, but if anyone has an idea on what’s going on I’d appreciate the help. I’d like my keypad back!

Edit: I should mention I’m using Dilbert66/esphome-components@main. I tried dev but got compilation errors about use of incomplete class. I can try again if you think that would help debug.

F7 20 00 03 10 08 00 1C 28 02 00 00 20 

Byte 3 (03) is the original mask representing keypad address 16 and 17 while byte 1 (20)
is I believe device address 5.
Looking at the following F7, you now have only address 16 active and added device 6 instead. You already had keypad 17 active before from what I see. Not sure why your main panel would stop working though as that should be at address 16 and that is still active.

F7 60 00 01 10 08 00 0C 2C 02 00 00 41 

Edit: I’ve corrected the dev branch compile issue. Either branch should work fine.
I suspect your main panel was using address 17 which is why it stopped working.
I looked up devices 5 and 6 and those are for AUI keypads (touchscreen i believe).
To see what address your keypad has, hold 1 and 3 together within 60 seconds of powering up the panel and it should show you the address it has. You can reassign it to be 16. you can lookup the procedure in the installers manual. I think you press 00 to clear and enter the new address then *.

1 Like

Thanks for your help/response!!

Could I somehow have changed my primary keypad to try to be a touchpad (it’s just a normal physical-button keypad)? I’ll check the address today.

Do you have an idea why this change is preventing my ESPHome device from forwarding on prompt messages? Both using keypadaddr1: 16 and keypadaddr1: 17 I don’t see the status messages update anymore after futzing with the programming, though I still see the status message in the logs

[08:18:03][E][CMD:843]: 1970-01-01 08:47  F7 60 00 01 10 08 00 0C 2C 02 00 00 41 
[08:18:03][E][INFO:1185]: Prompt: ARMED ***AWAY*** 
[08:18:03][E][INFO:1186]: Prompt: ** ALL SECURE **
[08:18:03][E][INFO:1187]: Beeps: 0

Edit: as you suspected, the keypad was configured as address 17. I reconfigured to 16 and it’s working again. Easy. In case it helps someone else, the full reprogramming sequence was:

  • Power cycle
  • Hold 1 & 3 until it shows the address
  • Type 00 16 *
    I still don’t understand why the firmware wasn’t sending the status messages, even when I set keypadaddr1: 16. But I’m all up and running now including the HA keypad and the physical keypad both working :tada:

Also I was able to switch to the dev branch. Thanks for fixing that!

Great that you have it fixed. As to the issue why it wasnt displaying for address 16 was a bug in my firmware. I have updated both main and dev with the revised fix.

1 Like

Great! Glad you solved the mystery! Thanks again for your help!

Longer term, any interest in potentially exposing this up as an ESPHome alarm_control_panel component? Then it would show up I think in HA as a standard alarm_control_panel type which would enable use of the stock Alarm Panel Card and the built in HA alarm services (e.g. alarm_control_panel.alarm_arm_away). This would standardize the core interface into your component (status, arming, disaarming) and you could still allow the user to expose zone sensors if they wanted. The code for a template alarm_control_panel would be the place to start for this.

No guarantees but I might be interested in helping out with that if it’d be of interest to you. I suppose I could shoe-horn this into an ESPHome template alarm_control_panel but that seems more geared towards building an alarm instead of exposing an existing one (e.g. it handles its own arming_away_time countdown).

The ability to use the stock alarm panel card is already available using HA template alarm control panel.

alarm_control_panel:
  - platform: template
    panels:
      safe_alarm_panel:
        name: "Alarm Panel"
        value_template: "{{states('sensor.vistaalarm_system_status')}}"
        code_arm_required: false
        
        arm_away:
          - service: esphome.vistaalarm_alarm_arm_away
                  
        arm_home:
          - service: esphome.vistaalarm_alarm_arm_home
          
        arm_night:
          - service: esphome.vistaalarm_alarm_arm_night
            data_template:
              code: '{{code}}' #if you didnt set it in the yaml, then send the code here
          
        disarm:
          - service: esphome.vistaalarm_alarm_disarm
            data_template:
              code: '{{code}}'      
1 Like

Neat thanks! I prefer to use the stock cards as much as possible (less to manage during updates). Here’s what I came up with (using one small custom variation on vertical-stack to remove the borders between cards)

type: custom:vertical-stack-in-card
cards:
  - states:
      - arm_home
      - arm_away
    type: alarm-panel
    entity: alarm_control_panel.safe_alarm_panel
  - type: markdown
    content: |-
      <center>{{ states('sensor.adtalarm_status_line_1') }}</center>
      <center>{{ states('sensor.adtalarm_status_line_2') }}</center>

One more thing I’d like to do is allow the user to disarm the alarm if they accidentally armed it. The problem is that the system_status entity doesn’t haven an arming state. I can handle that with some template magic, but it looks like the service call to esphome.alarmname_alarm_disarm is a noop if the system is not fully armed because of this line. What do you think about removing the second half of that if statement so disarms are always allowed (even if not armed, or in the process of arming). So this line:

else if (state.compare("D") == 0 && partitionStates[partition-1].previousLightState.armed) {

becomes

else if (state.compare("D") == 0) {

Here’s my full template in case it’s useful to someone else:

alarm_control_panel:
  - platform: template
    panels:
      safe_alarm_panel:
        name: "ADT Alarm"
        value_template: >-
          {% if 'May Exit Now' in states('sensor.adtalarm_status_line_2') %}
            arming
          {% else %}
            {{ states('sensor.adtalarm_system_status') }}
          {% endif %}
        code_arm_required: false

        arm_away:
          - service: esphome.adtalarm_alarm_arm_away
            data:
              partition: 1

        disarm:
          - service: esphome.adtalarm_alarm_disarm
            data:
              partition: 1
              code: "{{code}}"

Sure, no problem. I’ll remove the check.

Thank you! I moved back to main to pick up the change and just tested. Works great! Thank you!

Greetings! I picked this project back up and I seem to be in a worse state than I was initially months ago lol
I did update everything to the current release in master. And I updated my yaml file as well. All I see now in the log output is one of two things. When everything is ready to arm I see:

[22:08:37][I][CMD:588]: 2024-03-14 22:08  FB 02 20 81 62 00 00 00 00 00 00 00 00 
[22:08:38][I][CMD:588]: 2024-03-14 22:08  FB 02 20 80 5E 00 00 00 00 00 00 00 77 
[22:08:40][I][CMD:588]: 2024-03-14 22:08  72 41 00 00 00 00 00 00 00 00 00 00 00 

[22:08:44][I][CMD:588]: 2024-03-14 22:08  6D 41 00 00 00 00 00 00 00 00 00 00 00

About every 7 seconds I get the 72 or 6D. The pattern is inconsistent.
Completely randomly I’ll get a 79 (minutes apart)

When I open a door the every 7 second commands all go away and I’m left with only the FB:

[22:07:30][I][CMD:588]: 2024-03-14 22:07  FB 02 20 81 62 00 00 00 00 00 00 00 00 
[22:07:31][I][CMD:588]: 2024-03-14 22:07  FB 02 20 80 5E 00 00 00 00 00 00 00 77

there is absolutely nothing else in the log. I don’t see the prompt text anymore like I used to. I’m not sure where to even start with this. My esp component is set to keypad 20 which is enabled in the vista. I do have the funky xfinity takeover box on here so I’m not sure how that plays in exactly. I’m using the isolated circuit with the octocouplers.
Any help is much appreciated.

You should be seeing some f7’s always. Either you have a wiring /signal issue or your panel is doing odd things. It’s possible your version is non standard . I assume you have a vista20 from your previous posts. I suspect myself that you have an issue with the signal . The isolated version is not my recommended version as it is prone to signal problems due to insufficient gain with some optocouplers as well as adding unecessary load to the bus. This would cause similar issues to what you are seeing. A user created a version with pre amplification stage and reduced load but it adds complexity to the build. I would suggest you try the resistor divider version instead and see what results you have. It has a better signal output as well as providing minimal load to the bus.