diff --git a/pyhyypapi/__main__.py b/pyhyypapi/__main__.py index 736297e..8b5cc7d 100644 --- a/pyhyypapi/__main__.py +++ b/pyhyypapi/__main__.py @@ -1,4 +1,4 @@ -"""gcf example""" +"""Google Firebase push receiver example.""" from pyhyypapi.push_receiver import run_example if __name__ == "__main__": diff --git a/pyhyypapi/alarm_info.py b/pyhyypapi/alarm_info.py index 47dd8dc..5e03965 100644 --- a/pyhyypapi/alarm_info.py +++ b/pyhyypapi/alarm_info.py @@ -1,8 +1,10 @@ -"""Alarm info for hass integration""" +"""Alarm info for hass integration.""" from __future__ import annotations from typing import TYPE_CHECKING, Any +from .constants import EventNumber + if TYPE_CHECKING: from .client import HyypClient @@ -11,6 +13,7 @@ class HyypAlarmInfos: """Initialize Hyyp alarm objects.""" def __init__(self, client: HyypClient) -> None: + """init.""" self._client = client self._sync_info: dict = {} self._state_info: dict = {} @@ -20,6 +23,24 @@ def _fetch_data(self) -> None: self._sync_info = self._client.get_sync_info() self._state_info = self._client.get_state_info() + def _last_notice(self, site_id: str) -> dict[Any, Any]: + """Get last notification.""" + _response = {"dateTime": None, "eventName": None} + + _last_notification = self._client.site_notifications( + site_id=site_id, json_key=0 + ) + + _last_event = _last_notification["eventNumber"] + _last_event_datetime = _last_notification["dateTime"] + + _response = { + "dateTime": _last_event_datetime, + "eventName": EventNumber[str(_last_event)], + } + + return _response + def _format_data(self) -> dict[Any, Any]: """Format data for Hass.""" @@ -83,10 +104,15 @@ def _format_data(self) -> dict[Any, Any]: else: partition_ids[partition]["stayArmed"] = False + # Add last site notification. + partition_ids[partition]["lastNotification"] = self._last_notice( + site_id=str(list(partition_ids[partition]["site"])[0]) + ) + return partition_ids def status(self) -> dict[Any, Any]: - """Returns the status of Hyyp connected alarms.""" + """Return the status of Hyyp connected alarms.""" self._fetch_data() formatted_data: dict[Any, Any] = self._format_data() diff --git a/pyhyypapi/client.py b/pyhyypapi/client.py index 468547e..673e51b 100644 --- a/pyhyypapi/client.py +++ b/pyhyypapi/client.py @@ -6,9 +6,9 @@ import requests +from .alarm_info import HyypAlarmInfos from .constants import DEFAULT_TIMEOUT, REQUEST_HEADER, STD_PARAMS, HyypPkg from .exceptions import HTTPError, HyypApiError, InvalidURL -from .alarm_info import HyypAlarmInfos _LOGGER = logging.getLogger(__name__) @@ -24,6 +24,7 @@ API_ENDPOINT_SECURITY_COMPANIES = "/security-companies/list" API_ENDPOINT_STORE_GCM_REGISTRATION_ID = "/user/storeGcmRegistrationId" API_ENDPOINT_ARM_SITE = "/device/armSite" +API_ENDPOINT_TRIGGER_ALARM = "/device/triggerAlarm" API_ENDPOINT_SET_ZONE_BYPASS = "/device/bypass" API_ENDPOINT_GET_CAMERA_BY_PARTITION = "/device/getCameraByPartition" API_ENDPOINT_UPDATE_SUB_USER = "/user/updateSubUser" @@ -329,7 +330,7 @@ def get_sync_info(self, json_key: str = None) -> dict[Any, Any]: return _json_result[json_key] def get_state_info(self, json_key: str = None) -> dict[Any, Any]: - """Get state info from API. Returns armed, bypassed partition ids""" + """Get state info from API. Returns armed, bypassed partition ids.""" _params = STD_PARAMS @@ -710,6 +711,59 @@ def arm_site( return _json_result + # Untested. + def trigger_alarm( + self, + pin: int = None, + partition_id: int = None, + site_id: int = None, + trigger_id: int = None, + ) -> dict[Any, Any]: + """Trigger via API.""" + + if not site_id: + raise HyypApiError("Site ID Required") + + _params = STD_PARAMS.copy() + _params["pin"] = pin + _params["partitionId"] = partition_id + _params["siteId"] = site_id + _params["triggerId"] = trigger_id + del _params["imei"] + _params["clientImei"] = STD_PARAMS["imei"] + + try: + req = self._session.post( + "https://" + BASE_URL + API_ENDPOINT_TRIGGER_ALARM, + allow_redirects=False, + params=_params, + timeout=self._timeout, + ) + + req.raise_for_status() + + except requests.ConnectionError as err: + raise InvalidURL("A Invalid URL or Proxy error occured") from err + + except requests.HTTPError as err: + raise HTTPError from err + + try: + _json_result = req.json() + + except ValueError as err: + raise HyypApiError( + "Impossible to decode response: " + + str(err) + + "\nResponse was: " + + str(req.text) + ) from err + + if _json_result["status"] != "SUCCESS" and _json_result["error"] is not None: + raise HyypApiError(f"Trigger alarm failed: {_json_result['error']}") + + return _json_result + def set_zone_bypass( self, partition_id: int = None, diff --git a/pyhyypapi/constants.py b/pyhyypapi/constants.py index 86bafa0..c251ab1 100644 --- a/pyhyypapi/constants.py +++ b/pyhyypapi/constants.py @@ -1,5 +1,5 @@ """Hyyp API constants.""" -from enum import Enum, unique +from enum import Enum DEFAULT_TIMEOUT = 25 MAX_RETRIES = 3 @@ -42,95 +42,94 @@ class HyypPkg(Enum): IDS_HYYP_GENERIC = "com.hyyp247.home" -@unique -class EventNumber(Enum): - """EventNumber to name mapping.""" - - AC_CLOCK = 50 - AC_FAIL = 13 - AC_RESTORE = 24 - ALARM_CANCEL = 3 - ARMED_WITH_BYPASSED_ZONE = 7 - AUTO_ARM_CANCEL = 43 - AWAY_ARM = 0 - BATTERY_LOW = 17 - BATTERY_LOW_RESTORE = 28 - BOX_TAMPER = 20 - BOX_TAMPER_RESTORE = 31 - BUS_COMMS_FAIL = 22 - BUS_COMMS_RESTORE = 33 - BUS_DEVICE_BATTERY_LOW = 23 - BUS_DEVICE_BATTERY_RESTORE = 34 - BUS_DEVICE_TAMPER = 21 - BUS_DEVICE_TAMPER_RESTORE = 32 - COMMS_FAIL = 14 - COMM_RESTORE = 25 - CROSSED_ZONE_ALARM = 53 - CROSS_ZONE_TRIGGER = 89 - CRYSTAL_OSCILLATOR_CLOCK = 51 - DEDICATED_PANIC = 35 - DISARM = 2 - DISARM_FROM_STAY = 54 - DOWNLOAD_ACCESS = 37 - DTMF_LOGIN = 66 - DURESS = 38 - E12V_FUSE_FAIL = 18 - E12V_FUSE_RESTORE = 29 - ENGINEER_RESET = 19 - ENGINEER_RESET_RESTORE = 30 - ENTRY_DELAY = 88 - EXIT_DELAY = 85 - FAILED_IDSWIFT_LOGIN = 67 - FORCED_DOOR = 90 - INSTALLER_CODE_CHANGED = 52 - INSTALLER_MODE = 45 - KEYPAD_FIRE = 40 - KEYPAD_LOCKOUT = 42 - KEYPAD_MEDICAL = 41 - KEYPAD_PANIC = 39 - MPS_AC_FAIL = 79 - MPS_AC_RESTORE = 82 - MPS_BATT_LOW = 80 - MPS_BATT_RESTORE = 83 - MPS_FUSE_FAIL = 81 - MPS_FUSE_RESTORE = 84 - PANEL_DEFAULTED = 48 - PHONE_LINE_RESTORE = 26 - PHONE_LINE_TAMPER = 15 - POWER_UP = 47 - REMOTE_ARMING_REQUEST = 92 - REMOTE_PANIC = 93 - RESERVED = 49 - RF_DETECTOR_BATT_RESTORE = 72 - RF_DETECTOR_LOW_BATT = 68 - RF_DETECTOR_SUPERVISION_LOSS = 69 - RF_DETECTOR_SUPERVISION_RESTORE = 73 - RF_JAM = 70 - RF_JAM_RESTORE = 74 - RF_RSSI_LOW = 71 - RF_RSSI_RESTORE = 75 - SIREN_RESTORE = 27 - SIREN_TAMPER = 16 - STAY_ARM = 1 - STAY_ZONE_REPORT = 77 - SYSTEM_TROUBLE = 230 - SYSTEM_TROUBLE_RESTORE = 231 - TAG_ARMING_REQUEST = 91 - TAMPER_ALARM = 94 - TEMP_TRIGGER = 100 - TEMP_TRIGGER_ALARM = 101 - TEST_REPORT = 36 - TIME_STAMP = 78 - USER_BYPASSED_ZONES = 65 - USER_CODES_DEFAULTED = 46 - USER_CODE_CHANGED = 44 - USER_MENU_ACCESSED = 76 - USER_UNBYPASSED_ZONES = 87 - VOICE_LOGIN_LOCKOUT = 86 - ZONE_FORCED = 8 - ZONE_RESTORE = 6 - ZONE_SHUTDOWN = 11 - ZONE_SHUTDOWN_RESTORE = 12 - ZONE_TAMPER = 9 - ZONE_TAMPER_RESTORE = 10 - ZONE_VIOLATION_ALARM = 5 +# EventNumber to name mapping. +EventNumber = { + "50": "AC clock", + "13": "AC fail", + "24": "AC Restore", + "3": "Alarm cancel", + "7": "Armed with bypassed zone", + "43": "Auto arm cancel", + "0": "Away arm", + "17": "Battery low", + "28": "Battery low restore", + "20": "Box tamper", + "31": "Box tamper restore", + "22": "Bus comms fail", + "33": "Bus comms restore", + "23": "Bus device battery low", + "34": "Bus device battery restore", + "21": "Bus device tamper", + "32": "Bus device tamper restore", + "14": "Comms fail", + "25": "Comm restore", + "53": "Crossed zone alarm", + "89": "Cross zone trigger", + "51": "Crystal oscillator clock", + "35": "Dedicated panic", + "2": "Disarm", + "54": "Disarm from stay", + "37": "Download access", + "66": "DTMF login", + "38": "Duress", + "18": "12V fuse fail", + "29": "12V fuse restore", + "19": "Engineer reset", + "30": "Engineer reset restore", + "88": "Entry delay", + "85": "Exit delay", + "67": "Failed IDSwift login", + "90": "Forced door", + "52": "Installer code changed", + "45": "Installer mode", + "40": "Keypad fire", + "42": "Keypad lockout", + "41": "Keypad medical", + "39": "Keypad panic", + "79": "MPS AC fail", + "82": "MPS AC restore", + "80": "MPS batt low", + "83": "MPS Batt restore", + "81": "MPS Fuse fail", + "84": "MPS Fuse restore", + "48": "Panel defaulted", + "26": "Phone line restore", + "15": "Phone line tamper", + "47": "Power up", + "92": "Remote arming request", + "93": "Remote panic", + "49": "Reserved", + "72": "RF Detector batt restore", + "68": "RF Detector low batt", + "69": "RF Detector supervision loss", + "73": "RF Detector supervision restore", + "70": "RF Jam", + "74": "RF Jam restore", + "71": "Rf RSSI low", + "75": "RF RSSI restore", + "27": "Siren restore", + "16": "Siren tamper", + "1": "Stay arm", + "77": "Stay zone report", + "230": "System trouble", + "231": "System trouble restore", + "91": "TAG arming request", + "94": "Tamper alarm", + "100": "User trigger", + "101": "User panic", + "36": "Test report", + "78": "Time stamp", + "65": "User bypassed zones", + "46": "User codes defaulted", + "44": "User code changed", + "76": "User menu accessed", + "87": "User unbypassed zones", + "86": "Voice login lockout", + "8": "Force armed", + "6": "Zone restore", + "11": "Zone shutdown", + "12": "Zone shutdown restore", + "9": "Zone tamper", + "10": "Zone tamper restore", + "5": "Zone violation alarm", +} diff --git a/setup.py b/setup.py index 7c62704..ac3e9be 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name='pyhyypapi', - version="0.0.0.3", + version="0.0.0.4", license='Apache Software License 2.0', author='Renier Moorcroft', author_email='renierm26@users.github.com',