Standalone Alarm System with physical keypad

Looks like I was wrong! Zones 11-12 do work for Wiegand, so I guess them being inputs is enough after all (it was probably misconfigured before).

Great shout and you’re right. Unfortunately they do seem to be reused IDs. I’m guessing that the keypad itself can be secured but it’s enough to give me pause or at least dig a bit deeper. I might just use it to arm or something.

This was my original thought (especially given alarm-panel-pro-esp32-local-alarm.yaml in the repo, which I presume is what you adapted). But then in the Konnected docs (and release announcement), it suggests to use the “ESPHome Alarm Control Panel Component” instead. I had a look and it seems that it wraps up a lot of the state machine stuff. The following replaces the state machine and arm/disarm HA APIs:

alarm_control_panel:
  - platform: template
    name: Alarm panel
    id: acp1
    codes:
      - "${alarm_code}"
    binary_sensors: 
      - input: zone1
    on_triggered: 
      then:
        - switch.turn_on: alarm1
    on_cleared: 
      then:
        - switch.turn_off: alarm1

I’m not too familiar with the Konnected/ESPHome dichotomy but I suspect the app uses this component rather than the state machine approach? Your implementation does require access to the underlying state machine but the component exposes enough to get 99% of the way there - the main loss is the “toggle” transition. I made changes to the key_collector’s on_result as follows:

key_collector:
  - id: pincode_reader
    source_id: mykeypad
    min_length: 4
    max_length: 4
    end_keys: "#"
    end_key_required: false
    clear_keys: "*"
    allowed_keys: "0123456789"
    timeout: 5s
    on_progress:
      - logger.log:
          format: "input progress: '%s', started by '%c'"
          args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ]
    on_result:
      - logger.log:
          format: "input result: '%s', started by '%c', ended by '%c'"
          args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ]
      - if:
          condition:
            alarm_control_panel.is_armed: acp1
          then:
            lambda: id(acp1).disarm(std::string(x.c_str()));
          else:
            if:
              condition:
                lambda: return strcmp(x.c_str(), "${alarm_code}") == 0;
              then:
                lambda: id(acp1).arm_away();
    on_timeout:
      - logger.log:
          format: "input timeout: '%s', started by '%c'"
          args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ]