Skip to content

Instantly share code, notes, and snippets.

@runningman84
Last active February 10, 2018 22:10
Show Gist options
  • Save runningman84/b96a331b3486dbd1f5f2d00bc85d99ed to your computer and use it in GitHub Desktop.
Save runningman84/b96a331b3486dbd1f5f2d00bc85d99ed to your computer and use it in GitHub Desktop.
Appdaemon AlarmSystem
import appdaemon.appapi as appapi
#
# AlarmSystem App
#
# Args:
#
class AlarmSystem(appapi.AppDaemon):
def initialize(self):
self.log("Hello from AlarmSystem")
# setup sane defaults
self._armed_home_sensors = self.args.get("armed_home_sensors", [])
self._armed_away_sensors = self.args.get("armed_away_sensors", [])
self._device_trackers = self.args.get("device_trackers", [])
self._vacation_control = self.args.get("vacation_control", None)
self._guest_control = self.args.get("guest_control", None)
self._alarm_control_panel = self.args.get(
"alarm_control_panel", "alarm_control_panel.ha_alarm")
self._alarm_control_buttons = self.args.get(
"alarm_control_buttons", [])
self._alarm_lights = self.args.get("alarm_lights", [])
self._alarm_pin = self.args.get("alarm_pin", None)
self._alarm_volume_control = self.args.get(
"alarm_volume_control", None)
self._info_volume_control = self.args.get("info_volume_control", None)
self._silent_control = self.args.get("silent_control", None)
self._notify_service = self.args.get("notify_service", None)
self._notify_title = self.args.get(
"notify_title", "AlarmSystem triggered, possible intruder")
# xiaomi specific
self._xiaomi_aqara_gw_mac = self.args.get("xiaomi_aqara_gw_mac", None)
self._xiaomi_aqara_trggered_ringtone_id = self.args.get(
"xiaomi_aqara_trggered_ringtone_id", 2)
self._xiaomi_aqara_pending_ringtone_id = self.args.get(
"xiaomi_aqara_pending_ringtone_id", 10)
self._xiaomi_aqara_disarmed_ringtone_id = self.args.get(
"xiaomi_aqara_disarmed_ringtone_id", 11)
# log current config
self.log("Got armed_home sensors {}".format(
self._armed_home_sensors))
self.log("Got armed_away sensors {}".format(
self._armed_away_sensors))
self.log("Got device trackers {}".format(self._device_trackers))
self.log("Got {} device_trackers home and {} device_trackers not home".format(
self.count_home_device_trackers(), self.count_not_home_device_trackers()))
self.log("Got guest_mode {}".format(self.in_guest_mode()))
self.log("Got vacation_mode {}".format(self.in_vacation_mode()))
self.log("Got silent mode {}".format(self.in_silent_mode()))
self.log("Got info volume {}".format(self.get_info_volume()))
self.log("Got alarm volume {}".format(self.get_alarm_volume()))
self.log("Got notify service {}".format(self._notify_service))
self.log("Got alarm state {}".format(self.get_alarm_state()))
self.listen_state(self.alarm_state_triggered_callback,
self._alarm_control_panel, new="triggered")
self.listen_state(self.alarm_state_from_armed_home_to_pending_callback,
self._alarm_control_panel, old="armed_home", new="pending")
self.listen_state(self.alarm_state_from_armed_away_to_pending_callback,
self._alarm_control_panel, old="armed_away", new="pending")
self.listen_state(self.alarm_state_from_disarmed_to_pending_callback,
self._alarm_control_panel, old="disarmed", new="pending")
self.listen_state(self.alarm_state_disarmed_callback,
self._alarm_control_panel, new="disarmed")
self.listen_state(self.alarm_state_armed_away_callback,
self._alarm_control_panel, new="armed_away")
self.listen_state(self.alarm_state_armed_home_callback,
self._alarm_control_panel, new="armed_home")
for button in self._alarm_control_buttons:
self.listen_event(self.alarm_arm_home_button_callback,
'click', entity_id=button, click_type="single")
self.listen_event(self.alarm_disarm_button_callback,
'click', entity_id=button, click_type="double")
self.listen_event(self.alarm_arm_away_button_callback,
'click', entity_id=button, click_type="long_click_press")
# auto arm and disarm
i = 0
for sensor in self._device_trackers:
self.listen_state(self.alarm_arm_away_auto_callback, sensor,
new="not_home", duration=5 * 60 + i)
self.listen_state(self.alarm_disarm_auto_callback,
sensor, new="home", duration=i)
i += 1
self._flash_warning_handle = None
self._sensor_handles = {}
self.set_alarm_light_color_based_on_state()
def start_armed_home_sensors_listener(self):
for sensor in self._armed_home_sensors:
self._sensor_handles[sensor] = self.listen_state(
self.trigger_alarm_while_armed_home_callback, sensor, new="on", old="off")
def start_armed_away_sensors_listener(self):
for sensor in self._armed_away_sensors:
self._sensor_handles[sensor] = self.listen_state(
self.trigger_alarm_while_armed_away_callback, sensor, new="on", old="off")
def stop_sensors_listener(self):
for handle in self._sensor_handles:
if self._sensor_handles[handle] is not None:
self.cancel_timer(self._sensor_handles[handle] )
def count_doors_and_windows(self, state):
count = 0
for sensor in self._door_window_sensors:
if self.get_state(sensor) == state:
count = count + 1
return count
def count_open_doors_and_windows(self):
return self.count_doors_and_windows("on")
def count_closed_doors_and_windows(self):
return self.count_doors_and_windows("off")
def count_device_trackers(self, state):
count = 0
for sensor in self._device_trackers:
if self.get_state(sensor) == state:
count = count + 1
return count
def count_home_device_trackers(self):
return self.count_device_trackers("home")
def count_not_home_device_trackers(self):
return self.count_device_trackers("not_home")
def in_guest_mode(self):
if self._guest_control is None:
return False
if self.get_state(self._guest_control) == 'on':
return True
else:
return False
def in_vacation_mode(self):
if self._vacation_control is None:
return False
if self.get_state(self._vacation_control) == 'on':
return True
else:
return False
def get_alarm_volume(self):
if self._alarm_volume_control is None:
return 99
return int(float(self.get_state(self._alarm_volume_control)))
def get_info_volume(self):
if self._info_volume_control is None:
return 10
return int(float(self.get_state(self._info_volume_control)))
def get_xiaomi_aqara_gw_mac(self):
return self._xiaomi_aqara_gw_mac
def get_xiaomi_aqara_trggered_ringtone_id(self):
return self._xiaomi_aqara_trggered_ringtone_id
def get_xiaomi_aqara_pending_ringtone_id(self):
return self._xiaomi_aqara_pending_ringtone_id
def get_xiaomi_aqara_disarmed_ringtone_id(self):
return self._xiaomi_aqara_disarmed_ringtone_id
def in_silent_mode(self):
if self._silent_control is None:
return False
if self.get_state(self._silent_control) == 'on':
return True
else:
return False
def is_alarm_armed_away(self):
return self.is_alarm_in_state('armed_away')
def is_alarm_armed_home(self):
return self.is_alarm_in_state('armed_home')
def is_alarm_disarmed(self):
return self.is_alarm_in_state('disarmed')
def is_alarm_pending(self):
return self.is_alarm_in_state('pending')
def is_alarm_triggered(self):
return self.is_alarm_in_state('triggered')
def is_alarm_in_state(self, state):
if self._alarm_control_panel is None:
return False
if self.get_state(self._alarm_control_panel) == state:
return True
else:
return False
def get_alarm_state(self):
if self._alarm_control_panel is None:
return None
return self.get_state(self._alarm_control_panel)
def flash_warning(self, kwargs):
for light in self._alarm_lights:
self.toggle(light)
self.flashcount += 1
self.log("Flash warning count {}".format(self.flashcount))
if self.flashcount < 60:
self._flash_warning_handle = self.run_in(self.flash_warning, 1)
def set_alarm_light_color(self, color_name="green", brightness_pct=100):
for light in self._alarm_lights:
self.call_service(
"light/turn_on", entity_id=light, color_name=color_name, brightness_pct=brightness_pct)
def set_alarm_light_color_based_on_state(self):
if self.is_alarm_disarmed():
self.set_alarm_light_color("green", 15)
elif self.is_alarm_armed_away():
self.set_alarm_light_color("yellow", 25)
elif self.is_alarm_armed_home():
self.set_alarm_light_color("blue", 20)
elif self.is_alarm_triggered():
self.set_alarm_light_color("red", 100)
#elif self.is_alarm_pending():
#
def start_flash_warning(self, color_name="red", brightness_pct=100):
self.log("Starting flash warning with color {} and brightnes {}".format(
color_name, brightness_pct))
self.stop_flash_warning()
self.flashcount = 0
self.set_alarm_light_color(color_name, brightness_pct)
self._flash_warning_handle = self.run_in(self.flash_warning, 1)
def stop_flash_warning(self):
if self._flash_warning_handle is not None:
self.log("Stopping flash warning timer")
self.cancel_timer(self._flash_warning_handle)
self.flashcount = 60
self._flash_warning_handle = None
def alarm_state_triggered_callback(self, entity, attribute, old, new, kwargs):
self.log(
"Callback alarm_state_triggered from {}:{} {}->{}".format(entity, attribute, old, new))
if self.get_xiaomi_aqara_gw_mac() is not None and self.in_silent_mode() == False:
self.call_service("xiaomi_aqara/play_ringtone",
ringtone_id=self.get_xiaomi_aqara_trggered_ringtone_id(), ringtone_vol=self.get_alarm_volume(), gw_mac=self.get_xiaomi_aqara_gw_mac())
self.stop_flash_warning()
self.set_alarm_light_color_based_on_state()
if self._notify_service is not None:
self.call_service(self._notify_service, title=self._notify_title)
def alarm_state_from_armed_home_to_pending_callback(self, entity, attribute, old, new, kwargs):
self.log("Callback alarm_state_from_armed_home_to_pending from {}:{} {}->{}".format(
entity, attribute, old, new))
if self.get_xiaomi_aqara_gw_mac() is not None and self.in_silent_mode() == False:
self.call_service("xiaomi_aqara/play_ringtone",
ringtone_id=self.get_xiaomi_aqara_pending_ringtone_id(), ringtone_vol=self.get_info_volume(), gw_mac=self.get_xiaomi_aqara_gw_mac())
self.start_flash_warning("red")
def alarm_state_from_armed_away_to_pending_callback(self, entity, attribute, old, new, kwargs):
self.log("Callback alarm_state_from_armed_away_to_pending from {}:{} {}->{}".format(
entity, attribute, old, new))
if self.get_xiaomi_aqara_gw_mac() is not None and self.in_silent_mode() == False:
self.call_service("xiaomi_aqara/play_ringtone",
ringtone_id=self.get_xiaomi_aqara_pending_ringtone_id(), ringtone_vol=self.get_info_volume(), gw_mac=self.get_xiaomi_aqara_gw_mac())
self.start_flash_warning("red")
def alarm_state_from_disarmed_to_pending_callback(self, entity, attribute, old, new, kwargs):
self.log("Callback alarm_state_from_disarmed_to_pending from {}:{} {}->{}".format(
entity, attribute, old, new))
if self.get_xiaomi_aqara_gw_mac() is not None and self.in_silent_mode() == False:
self.call_service("xiaomi_aqara/play_ringtone",
ringtone_id=self.get_xiaomi_aqara_pending_ringtone_id(), ringtone_vol=self.get_info_volume(), gw_mac=self.get_xiaomi_aqara_gw_mac())
self.start_flash_warning("yellow", 50)
def alarm_state_disarmed_callback(self, entity, attribute, old, new, kwargs):
self.log(
"Callback alarm_state_disarmed from {}:{} {}->{}".format(entity, attribute, old, new))
if self.get_xiaomi_aqara_gw_mac() is not None and self.in_silent_mode() == False:
self.call_service("xiaomi_aqara/stop_ringtone",
gw_mac=self.get_xiaomi_aqara_gw_mac())
self.call_service("xiaomi_aqara/play_ringtone",
ringtone_id=self.get_xiaomi_aqara_disarmed_ringtone_id(), ringtone_vol=self.get_info_volume(), gw_mac=self.get_xiaomi_aqara_gw_mac())
self.stop_flash_warning()
self.stop_sensors_listener()
self.set_alarm_light_color_based_on_state()
def alarm_state_armed_away_callback(self, entity, attribute, old, new, kwargs):
self.log(
"Callback alarm_state_armed_away from {}:{} {}->{}".format(entity, attribute, old, new))
if self.get_xiaomi_aqara_gw_mac() is not None and self.in_silent_mode() == False:
self.call_service("xiaomi_aqara/stop_ringtone",
gw_mac=self.get_xiaomi_aqara_gw_mac())
self.stop_flash_warning()
self.stop_sensors_listener()
self.start_armed_away_sensors_listener()
self.set_alarm_light_color_based_on_state()
def alarm_state_armed_home_callback(self, entity, attribute, old, new, kwargs):
self.log(
"Callback alarm_state_armed_home from {}:{} {}->{}".format(entity, attribute, old, new))
if self.get_xiaomi_aqara_gw_mac() is not None and self.in_silent_mode() == False:
self.call_service("xiaomi_aqara/stop_ringtone",
gw_mac=self.get_xiaomi_aqara_gw_mac())
self.stop_flash_warning()
self.stop_sensors_listener()
self.start_armed_home_sensors_listener()
self.set_alarm_light_color_based_on_state()
def trigger_alarm_while_armed_away_callback(self, entity, attribute, old, new, kwargs):
self.log(
"Callback trigger_alarm_while_armed_away from {}:{} {}->{}".format(entity, attribute, old, new))
if(self.is_alarm_armed_away() == False):
self.log("Ignoring status {} of {} because alarm system is in state {}".format(
new, entity, self.get_alarm_state()))
return
self.call_service("alarm_control_panel/alarm_trigger",
entity_id=self._alarm_control_panel)
def trigger_alarm_while_armed_home_callback(self, entity, attribute, old, new, kwargs):
self.log(
"Callback trigger_alarm_while_armed_home from {}:{} {}->{}".format(entity, attribute, old, new))
if(self.is_alarm_armed_home() == False):
self.log("Ignoring status {} of {} because alarm system is in state {}".format(
new, entity, self.get_alarm_state()))
return
self.call_service("alarm_control_panel/alarm_trigger",
entity_id=self._alarm_control_panel)
def alarm_arm_away_button_callback(self, event_name, data, kwargs):
self.log("Callback alarm_arm_away_button_callback from {}:{} {}".format(
event_name, data['entity_id'], data['click_type']))
if(self.is_alarm_disarmed() == False):
self.log("Ignoring event {} of {} because alarm system is in state {}".format(
event_name, data['entity_id'], self.get_alarm_state()))
return
self.call_service("alarm_control_panel/alarm_arm_away",
entity_id=self._alarm_control_panel, code=self._alarm_pin)
def alarm_disarm_button_callback(self, event_name, data, kwargs):
self.log("Callback alarm_disarm_button_callback from {}:{} {}".format(
event_name, data['entity_id'], data['click_type']))
if(self.is_alarm_disarmed()):
self.log("Ignoring event {} of {} because alarm system is in state {}".format(
event_name, data['entity_id'], self.get_alarm_state()))
return
self.call_service("alarm_control_panel/alarm_disarm",
entity_id=self._alarm_control_panel, code=self._alarm_pin)
def alarm_arm_home_button_callback(self, event_name, data, kwargs):
self.log("Callback alarm_arm_home_button from {}:{} {}".format(
event_name, data['entity_id'], data['click_type']))
if(self.is_alarm_disarmed() == False):
self.log("Ignoring event {} of {} because alarm system is in state {}".format(
event_name, data['entity_id'], self.get_alarm_state()))
return
self.call_service("alarm_control_panel/alarm_arm_home",
entity_id=self._alarm_control_panel, code=self._alarm_pin)
def alarm_arm_away_auto_callback(self, entity, attribute, old, new, kwargs):
self.log(
"Callback alarm_arm_away_auto from {}:{} {}->{}".format(entity, attribute, old, new))
if(self.is_alarm_disarmed() == False):
self.log("Ignoring status {} of {} because alarm system is in state {}".format(
new, entity, self.get_alarm_state()))
return
if(self.count_home_device_trackers() > 0):
self.log("Ignoring status {} of {} because {} device_trackers are still at home".format(
new, entity, self.count_home_device_trackers()))
return
if(self.in_guest_mode()):
self.log("Ignoring status {} of {} because {} we have guests".format(
new, entity, self.count_home_device_trackers()))
return
self.call_service("alarm_control_panel/alarm_arm_away",
entity_id=self._alarm_control_panel, code=self._alarm_pin)
def alarm_disarm_auto_callback(self, entity, attribute, old, new, kwargs):
self.log(
"Callback alarm_disarm_auto from {}:{} {}->{}".format(entity, attribute, old, new))
if(self.is_alarm_armed_away() == False):
self.log("Ignoring status {} of {} because alarm system is in state {}".format(
new, entity, self.get_alarm_state()))
return
self.call_service("alarm_control_panel/alarm_disarm",
entity_id=self._alarm_control_panel, code=self._alarm_pin)
alarm_system:
module: alarm
class: AlarmSystem
device_trackers:
- device_tracker.android_phone_bob
- device_tracker.android_phone_jon
armed_home_sensors:
- binary_sensor.door_window_sensor_158d0001111111
- binary_sensor.door_window_sensor_158d0001222222
- binary_sensor.door_window_sensor_158d0001333333
armed_away_sensors:
- binary_sensor.door_window_sensor_158d0001111111
- binary_sensor.door_window_sensor_158d0001222222
- binary_sensor.door_window_sensor_158d0001333333
- binary_sensor.motion_sensor_158d000111111
- binary_sensor.motion_sensor_158d000222222
alarm_control_buttons:
- binary_sensor.switch_158d0001111111
- binary_sensor.switch_158d0002222222
- binary_sensor.switch_158d0003333333
alarm_lights:
- light.gateway_light_1111111
alarm_pin: 1234
vacation_control: input_boolean.vacation_mode
guest_control: input_boolean.guest_mode
silent_control: input_boolean.silent_mode
alarm_volume_control: input_number.xiaomi_alarm_volume
info_volume_control: input_number.xiaomi_info_volume
xiaomi_aqara_gw_mac: f00000000
notify_service: script/send_status_report_bob
notify_title: "Intruder Alert"
input_boolean:
vacation_mode:
initial: off
guest_mode:
initial: off
silent_mode:
initial: off
input_number:
xiaomi_alarm_volume:
name: Alarm volume
initial: 100
min: 1
max: 100
step: 1
xiaomi_info_volume:
name: Info volume
initial: 10
min: 1
max: 100
step: 1
alarm_control_panel:
- platform: manual
code: !secret alarm_pin
pending_time: 30
# https://home-assistant.io/cookbook/#example-configurationyaml
send_status_report_philipp:
alias: "Send status report philipp"
sequence:
- service: notify.smtp_gmail_philipp
data_template:
title: >
{% if title %}
{{title}}
{% else %}
Status Report
{% endif %}
message: "
Adresse:
...
Status Alarmanlage:
- {{ states('alarm_control_panel.ha_alarm') }} -
Alarmierte Rauchmelder:
{% for state in states if state.attributes.device_class == 'smoke' and state.state == 'on' -%}
- {{ state.name.split(' ',1)[1] }} seit {{ as_timestamp(state.last_changed) | timestamp_local }}
{% else -%}
- keine -
{% endfor %}
Rauchabzug Flur:
{% if is_state('binary_sensor.door_window_sensor_158d00018339c3', 'on') %}
- geöffnet -
{%- else %}
- geschlossen -
{% endif %}
Anwesende Personen:
{% for state in states.device_tracker if '_phone_' in state.entity_id and state.state == 'home' -%}
- {{ state.name.split(' ',1)[1] }} seit {{ as_timestamp(state.last_changed) | timestamp_local }}
{% else %}
- keine -
{% endfor %}
Aktive Bewegungsmelder:
{% for state in states if state.attributes.device_class == 'motion' and state.state == 'on' -%}
- {{ state.name.split(' ',1)[1] }}
{% else -%}
- keine -
{% endfor %}
Offene Türen:
{% for state in states if state.attributes.device_class == 'opening' and 'Fenster' not in state.attributes.friendly_name and state.state == 'on' -%}
- {{ state.name.split(' ',1)[1] }} seit {{ as_timestamp(state.last_changed) | timestamp_local }}
{% else -%}
- keine -
{% endfor %}
Offene Fenster:
{% for state in states if state.attributes.device_class == 'opening' and 'Tür' not in state.attributes.friendly_name and state.state == 'on' -%}
- {{ state.name.split(' ',1)[1] }} seit {{ as_timestamp(state.last_changed) | timestamp_local }}
{% else -%}
- keine -
{% endfor %}
Temperaturen:
{% for state in states.climate -%}
- {{state.attributes.current_temperature}} {{state.attributes.unit_of_measurement}} {{ state.name.split(' ',1)[1] }}
{% else -%}
- keine -
{% endfor -%}
{% for state in states.sensor if 'temperature_' in state.entity_id -%}
- {{state.state | round(1)}} {{state.attributes.unit_of_measurement}} {{ state.name.split(' ',1)[1]
}}
{% else -%}
- keine -
{% endfor %}
"
data:
images:
- /camera/camera.flur_unten_latest_0.jpg
- /camera/camera.flur_unten_latest_1.jpg
- /camera/camera.flur_unten_latest_2.jpg
- /camera/camera.flur_unten_latest_3.jpg
- /camera/camera.flur_unten_latest_4.jpg
send_status_report_philipp:
alias: "Send status report philipp"
sequence:
- service: notify.smtp_gmail_philipp
data_template:
title: "AlertSystem triggered"
message: "please check for intruders"
@runningman84
Copy link
Author

hi andyinno,
that's a great idea...

here is my new github repo:
https://github.com/runningman84/home-assistant-apps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment